【离散数学】高级计数技术
2018-03-08 19:13
916 查看
这是离散数学的第四篇,讨论高级计数技术。同步发布与个人博客,上一篇(【离散数学】计数/排列组合)讨论了计数以及排列组合,二项式定理等。但是仅凭排列组合等手段依然无法解决许多计数问题。这里首先讨论通过递推关系来求解计数问题,并介绍有递推关系引出的两个算法范式:动态规划和分治。这两种算法均是通过将问题分割为一系列的子问题来求解的,区别就是前者分割出来的子问题互相重叠,后者的子问题不重叠。这是两种很重要的算法,加上贪心、回溯、分支定界为五种很常用的算法。这里仅仅简单讨论思路,并分析其复杂度。关于具体的算法分析以及算法设计以后应该会讨论。而后介绍了求解一类很常见的特定递推关系——常系数线性齐次与非齐次递推关系的形式解法。并且还介绍了一种求解计数问题的很重要的手段——生成函数,这是幂级数的应用。最后介绍容斥原理,对,就是集合的容斥原理。以上内容以前均有涉及,这里再次探讨。
![](http://oxx8it1qo.bkt.clouddn.com/towel-of-hanoi.jpg)
n=3的汉诺塔移动方法:
![](http://oxx8it1qo.bkt.clouddn.com/hanoi-towel.gif)
令移动n个盘子到另一个柱子所需最少次数为 HnHn ,考虑最下面一个最大的盘子,由于小的盘子不能放在大的盘子下面,所以必须首先将上面n-1个移动到另一个柱子,再将最下面的最大的一个移动到另一根柱子,再将n-1个移到其上,则完成了n个盘子的移动。则得到递推关系 Hn=2Hn−1+1Hn=2Hn−1+1。初始条件很容易知道:H0=0H0=0,H1=1H1=1。
求解递推关系:容易看出 Hn+1=2(Hn−1+1)Hn+1=2(Hn−1+1),可以得到 Hn=2n−1Hn=2n−1。可以证明这便是移动n个盘子所需的最少次数。
20000
/span>x0⋅x1⋅x2⋯xn 的乘积中插入括号来规定乘法次序的方式数,令其为 CnCn。
这里注意到一定会有一个乘法是在括号外面的(不需要加括号),假设其在xkxk和xk+1xk+1之间,则存在CkCn−k−1CkCn−k−1种方式,考虑最后一个乘号可能取n个位置,则有Cn=∑k=0n−1CkCn−k−1Cn=∑k=0n−1CkCn−k−1
初始条件则为C0=1C0=1,C1=1C1=1。
利用生成函数的方法可以证明:Cn=C(2n,n)n+1Cn=C(2n,n)n+1,被称作第n个卡特兰(Catalan)数,序列{Cn}{Cn} 被称为卡特兰数的序列。参见 OEIS A000108,Catalan number - Wikipedia。
为了求解kk阶常系数线性齐次递推关系,这里的基本方法是寻找形如an=rnan=rn的解,其中r是常数。递推关系要有形如an=rnan=rn的解,则当且仅当rr是方程rk−c1rk−1−c2rk−2−⋯−ck−1r−ck=0rk−c1rk−1−c2rk−2−⋯−ck−1r−ck=0的解。
将上述方程称为该递推关系的特征方程。方程的解称为特征根。(与求解常系数线性微分方程如出一辙)。特征根有可能是复数,但这里仅考虑特征根为实数的情况。
定理:假设特征方程rk−c1rk−1−⋯−ck=0rk−c1rk−1−⋯−ck=0有k个不相等的根r1,r2,...,rkr1,r2,...,rk。那么递推关系an=c1an−1+c2an−2+⋯+ckan−kan=c1an−1+c2an−2+⋯+ckan−k的解为an=α1rn1+α2rn2+⋯+αkrnkan=α1r1n+α2r2n+⋯+αkrkn
n∈N,α1,α2,...,αkn∈N,α1,α2,...,αk是常数。
另外,对其中的每一个特征根riri,如果并非一重而是mimi重时,则用 (αi,0+αi,1n+⋯+αi,mi−1nmi−1)rni(αi,0+αi,1n+⋯+αi,mi−1nmi−1)rin 替代 上述解中的αirniαirin即可。
例:斐波那契数列(OEIS A000045)
递推关系fn=fn−1+fn−2fn=fn−1+fn−2,初始条件f0=0,f1=1f0=0,f1=1。
特征方程r2−r−1=0r2−r−1=0 根为 r1=(1+5–√)/2r1=(1+5)/2,r2=(1−5–√)/2r2=(1−5)/2。
则fn=α1(1+5–√2)n+α2(1−5–√2)nfn=α1(1+52)n+α2(1−52)n代入f0,f1f0,f1解出α1=15–√α1=15,α2=−15–√α2=−15
则得到斐波那契数列的显式公式为fn=15–√(1+5–√2)n−15–√(1−5–√2)nfn=15(1+52)n−15(1−52)n
齐次解即对应的常系数线性齐次递推关系的解,记作a(h)nan(h),特解记作a(p)nan(p)。
不同形式的F(n)具有不同形式的特解
若 F(n)F(n) 形如 (btnt+bt−1nt−1+⋯+b1n+b0)sn(btnt+bt−1nt−1+⋯+b1n+b0)sn.
则当 ss 不是特征根时,特解形如 (ptnt+pt−1nt−1+⋯+p1n+p0)sn(ptnt+pt−1nt−1+⋯+p1n+p0)sn.
当 ss 是mm重特征根时,特解形如 nm(ptnt+pt−1nt−1+⋯+p1n+p0)snnm(ptnt+pt−1nt−1+⋯+p1n+p0)sn.
令n=bkn=bk,多次迭代后可以得到:
f(n)=akf(1)+∑j=0k−1ajg(n/bj)f(n)=akf(1)+∑j=0k−1ajg(n/bj)
很容易知道,
二分查找的分治递推关系:f(n)=f(n/2)+2f(n)=f(n/2)+2
归并排序的分治递推关系:M(n)=2M(n/2)+nM(n)=2M(n/2)+n
bb是大于1的整数,cc是正实数。那么
f(n)={O(nlogba)O(logn)a>1a=1f(n)={O(nlogba)a>1O(logn)a=1证明:令n=bkn=bk即可证得,当n≠bkn≠bk时,依然成立。
很容易得出二分查找复杂度为O(logn)O(logn)。
主定理:若f(n)=af(n/b)+cndf(n)=af(n/b)+cnd,则f(n)=⎧⎩⎨⎪⎪O(nd)O(ndlogn)O(nlogba)a<bda=bda≻bdf(n)={O(nd)a<bdO(ndlogn)a=bdO(nlogba)a≻bd
同理,令n=bkn=bk即可证得。(ps:上面的≻≻表示大于号,但其实这个符号并不是这个意思。这里有一个bug,hexo自带一个功能的会把一段内连续的<>之间的内容注释掉,于是就只好将就一下。)
根据主定理,很容易得出归并排序复杂度为O(nlogn)O(nlogn)。
可以看到,定理1只是主定理的特殊情况。
这里仅简单分析分治算法,并解决了其复杂度的问题,并未涉及分治算法的设计及具体实现。
例:序列{C(n,k)}{C(n,k)}的生成函数即是G(x)=(1+x)nG(x)=(1+x)n.
使用生成函数求解计数问题时,通常考虑形式幂级数,即不需要考虑其收敛域(对发散或收敛并不感兴趣)
uu为实数,kk为非负整数,广义二项式系数定义为
(uk)={u(u−1)⋯(u−k−1)/k!1k>0k=0(ku)={u(u−1)⋯(u−k−1)/k!k>01k=0
当u为负整数时,展开即可有下列式子成立(−nk)=(−1)rC(n+r−1,r)(k−n)=(−1)rC(n+r−1,r)
广义二项式定理:
xx是实数,|x|<1|x|<1,uu 是实数,那么(1+x)u=∑k=0∞(uk)xk(1+x)u=∑k=0∞(ku)xk
其实这就是(1+x)u(1+x)u的幂级数展开,使用麦克劳林级数(即在x=0处泰勒展开)即可证明。
(1). (1+ax)n=∑nk=0C(n,k)akxk(1+ax)n=∑k=0nC(n,k)akxk,ak=C(n,k)akak=C(n,k)ak,二项式定理得到
(2). 1−xr+11−x=∑nk=0xk1−xr+11−x=∑k=0nxk,ak=1,k⩽nak=1,k⩽n;否则为0,几何级数求和得到
(3). 11−ax=∑∞k=0akxk11−ax=∑k=0∞akxk,ak=akak=ak,对|x|<1|x|<1的几何级数求和取极限得到
(4). 1(1−x)2=∑∞k=0(k+1)xk1(1−x)2=∑k=0∞(k+1)xk,ak=k+1ak=k+1,对11−x11−x求导得到
(5). 1(1−x)n=∑∞k=0C(n+k−1,k)xk1(1−x)n=∑k=0∞C(n+k−1,k)xk,ak=C(n+k−1,k)=C(n+k−1,n−1)ak=C(n+k−1,k)=C(n+k−1,n−1),由广义二项式定理得到
(6). ex=∑∞k=0xkk!ex=∑k=0∞xkk!,ak=1/k!ak=1/k!,泰勒展开即可得到
(7). ln(1+x)=∑∞k=0(−1)k+1kxkln(1+x)=∑k=0∞(−1)k+1kxk,ak=(−1)k+1/kak=(−1)k+1/k,同上泰勒展开得到
生成函数可以用来求解计数问题,还可以用来求解递推关系和证明组合恒等式。这里不想写了,略过吧!(笑)
可以看到加号和减号是交替出现的,保证了没有遗漏也没有重复。
三个集合的容斥原理:
![](https://upload.wikimedia.org/wikipedia/commons/4/42/Inclusion-exclusion.svg)
![](https://wikimedia.org/api/rest_v1/media/math/render/svg/0b8e7c1631ec013eed94feb5aa406a573caa3559)
应用很多,此处愉快地略过。
逐步积累,随性记录,知道自己要去的地方、要走的路,一直写着就好。——201.3.7
参考资料:《离散数学及其应用》(本科教学版,Kenneth H.Rosen著,原书第七版)
递推关系的应用
经典问题——汉诺塔
这是一个及其经典的问题,见汉诺塔(Tower of Hanoi),三根柱子,n个盘子,从上到下盘子从小到大。将所有n个盘子从一根柱子移动到另一根柱子,移动过程中小的盘子不能放在大的盘子下面。可以求解出所需要的最小步数,还可以编写算法打印出所有步数。![](http://oxx8it1qo.bkt.clouddn.com/towel-of-hanoi.jpg)
n=3的汉诺塔移动方法:
![](http://oxx8it1qo.bkt.clouddn.com/hanoi-towel.gif)
令移动n个盘子到另一个柱子所需最少次数为 HnHn ,考虑最下面一个最大的盘子,由于小的盘子不能放在大的盘子下面,所以必须首先将上面n-1个移动到另一个柱子,再将最下面的最大的一个移动到另一根柱子,再将n-1个移到其上,则完成了n个盘子的移动。则得到递推关系 Hn=2Hn−1+1Hn=2Hn−1+1。初始条件很容易知道:H0=0H0=0,H1=1H1=1。
求解递推关系:容易看出 Hn+1=2(Hn−1+1)Hn+1=2(Hn−1+1),可以得到 Hn=2n−1Hn=2n−1。可以证明这便是移动n个盘子所需的最少次数。
卡特兰数
考虑一个在n+1个数 x0⋅x1⋅x2⋯xn<20000
/span>x0⋅x1⋅x2⋯xn 的乘积中插入括号来规定乘法次序的方式数,令其为 CnCn。
这里注意到一定会有一个乘法是在括号外面的(不需要加括号),假设其在xkxk和xk+1xk+1之间,则存在CkCn−k−1CkCn−k−1种方式,考虑最后一个乘号可能取n个位置,则有Cn=∑k=0n−1CkCn−k−1Cn=∑k=0n−1CkCn−k−1
初始条件则为C0=1C0=1,C1=1C1=1。
利用生成函数的方法可以证明:Cn=C(2n,n)n+1Cn=C(2n,n)n+1,被称作第n个卡特兰(Catalan)数,序列{Cn}{Cn} 被称为卡特兰数的序列。参见 OEIS A000108,Catalan number - Wikipedia。
动态规划与递推关系
动态规划(Dynamic programming,DP)是一种算法范式,遵循动态规划范式的算法是将原问题分解为更简单的重叠的子问题,通过子问题的求解来求解原问题。常用于求解最短路线、库存管理、资源分配、设备更新、排序、装载等问题。此类问题若用分治法来解,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。所以DP通过保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,从而降低复杂度。以后单独讨论,这里推荐阅读:动态规划解决01背包问题,什么是动态规划?动态规划的意义是什么?。求解线性递推关系
这部分给人的感觉相当熟悉,在高等数学中有线性微分方程的求解,线性代数中有线性方程组的求解,与这里的线性递推关系的求解十分类似,可以说是如出一辙。求解常系数线性齐次递推关系
一个常系数的kk阶线性齐次递推关系指的是形如 an=c1an−1+c2an−2+⋯+ckan−kan=c1an−1+c2an−2+⋯+ckan−k,的递推关系,其中cici为实数,ck≠0ck≠0。为了求解kk阶常系数线性齐次递推关系,这里的基本方法是寻找形如an=rnan=rn的解,其中r是常数。递推关系要有形如an=rnan=rn的解,则当且仅当rr是方程rk−c1rk−1−c2rk−2−⋯−ck−1r−ck=0rk−c1rk−1−c2rk−2−⋯−ck−1r−ck=0的解。
将上述方程称为该递推关系的特征方程。方程的解称为特征根。(与求解常系数线性微分方程如出一辙)。特征根有可能是复数,但这里仅考虑特征根为实数的情况。
定理:假设特征方程rk−c1rk−1−⋯−ck=0rk−c1rk−1−⋯−ck=0有k个不相等的根r1,r2,...,rkr1,r2,...,rk。那么递推关系an=c1an−1+c2an−2+⋯+ckan−kan=c1an−1+c2an−2+⋯+ckan−k的解为an=α1rn1+α2rn2+⋯+αkrnkan=α1r1n+α2r2n+⋯+αkrkn
n∈N,α1,α2,...,αkn∈N,α1,α2,...,αk是常数。
另外,对其中的每一个特征根riri,如果并非一重而是mimi重时,则用 (αi,0+αi,1n+⋯+αi,mi−1nmi−1)rni(αi,0+αi,1n+⋯+αi,mi−1nmi−1)rin 替代 上述解中的αirniαirin即可。
例:斐波那契数列(OEIS A000045)
递推关系fn=fn−1+fn−2fn=fn−1+fn−2,初始条件f0=0,f1=1f0=0,f1=1。
特征方程r2−r−1=0r2−r−1=0 根为 r1=(1+5–√)/2r1=(1+5)/2,r2=(1−5–√)/2r2=(1−5)/2。
则fn=α1(1+5–√2)n+α2(1−5–√2)nfn=α1(1+52)n+α2(1−52)n代入f0,f1f0,f1解出α1=15–√α1=15,α2=−15–√α2=−15
则得到斐波那契数列的显式公式为fn=15–√(1+5–√2)n−15–√(1−5–√2)nfn=15(1+52)n−15(1−52)n
求解常系数线性非齐次递推关系
常系数线性非齐次递推关系:形如 an=c1an−1+c2an−2+⋯+ckan−k+F(n)an=c1an−1+c2an−2+⋯+ckan−k+F(n),与其相伴的齐次递推关系为 an=c1an−1+c2an−2+⋯+ckan−kan=c1an−1+c2an−2+⋯+ckan−k,很显然 通解 = 特解+齐次解。齐次解即对应的常系数线性齐次递推关系的解,记作a(h)nan(h),特解记作a(p)nan(p)。
不同形式的F(n)具有不同形式的特解
F(n)F(n) | 特解形式 |
---|---|
an+ban+b | cn+dcn+d |
α⋅cnα⋅cn | β⋅cnβ⋅cn |
则当 ss 不是特征根时,特解形如 (ptnt+pt−1nt−1+⋯+p1n+p0)sn(ptnt+pt−1nt−1+⋯+p1n+p0)sn.
当 ss 是mm重特征根时,特解形如 nm(ptnt+pt−1nt−1+⋯+p1n+p0)snnm(ptnt+pt−1nt−1+⋯+p1n+p0)sn.
分治算法与递推关系
与动态规划相似,分治算法(Divide and conquer algorithm)范式也会将问题划分为一个或者多个小问题,不过这些小问题是不重叠的。连续使用这种划分直到可以快速找到这些小问题的解,然后将小问题的解合并为原问题的解。即三个步骤:分割原问题,解决子问题,合并得到最终解。常见简单分治算法:归并排序、二分查找。这里将说明怎样用递关系来分析分治算法的复杂度。分治递推关系
假设一个递归算法将规模为n的问题划分为a个子问题,每个子问题规模为n/b,并且需要g(n)的额外运算来合并这些子问题。用f(n)表示求解问题规模为n的问题所需运算数,则f(n)=af(n/b)+g(n)f(n)=af(n/b)+g(n)令n=bkn=bk,多次迭代后可以得到:
f(n)=akf(1)+∑j=0k−1ajg(n/bj)f(n)=akf(1)+∑j=0k−1ajg(n/bj)
很容易知道,
二分查找的分治递推关系:f(n)=f(n/2)+2f(n)=f(n/2)+2
归并排序的分治递推关系:M(n)=2M(n/2)+nM(n)=2M(n/2)+n
分治算法的复杂度分析
定理1:设f(n)f(n)是满足f(n)=af(n/b)+cf(n)=af(n/b)+c 的增函数,nn被bb整除,a⩾1a⩾1,bb是大于1的整数,cc是正实数。那么
f(n)={O(nlogba)O(logn)a>1a=1f(n)={O(nlogba)a>1O(logn)a=1证明:令n=bkn=bk即可证得,当n≠bkn≠bk时,依然成立。
很容易得出二分查找复杂度为O(logn)O(logn)。
主定理:若f(n)=af(n/b)+cndf(n)=af(n/b)+cnd,则f(n)=⎧⎩⎨⎪⎪O(nd)O(ndlogn)O(nlogba)a<bda=bda≻bdf(n)={O(nd)a<bdO(ndlogn)a=bdO(nlogba)a≻bd
同理,令n=bkn=bk即可证得。(ps:上面的≻≻表示大于号,但其实这个符号并不是这个意思。这里有一个bug,hexo自带一个功能的会把一段内连续的<>之间的内容注释掉,于是就只好将就一下。)
根据主定理,很容易得出归并排序复杂度为O(nlogn)O(nlogn)。
可以看到,定理1只是主定理的特殊情况。
这里仅简单分析分治算法,并解决了其复杂度的问题,并未涉及分治算法的设计及具体实现。
生成函数
表示序列的一个有效方法是生成函数,把序列的项作为形式幂级数的变量x的幂的系数。可以用生成函数解决许多类型的计数问题。拓展阅读:Generating function - Wikipedia,什么是生成函数? | Matrix67: The Aha Moments。定义
实数序列a0,a1,...,ak,...a0,a1,...,ak,...的(普通)生成函数是无穷级数G(x)=∑k=0∞akxkG(x)=∑k=0∞akxk例:序列{C(n,k)}{C(n,k)}的生成函数即是G(x)=(1+x)nG(x)=(1+x)n.
使用生成函数求解计数问题时,通常考虑形式幂级数,即不需要考虑其收敛域(对发散或收敛并不感兴趣)
广义二项式定理
广义二项式系数:uu为实数,kk为非负整数,广义二项式系数定义为
(uk)={u(u−1)⋯(u−k−1)/k!1k>0k=0(ku)={u(u−1)⋯(u−k−1)/k!k>01k=0
当u为负整数时,展开即可有下列式子成立(−nk)=(−1)rC(n+r−1,r)(k−n)=(−1)rC(n+r−1,r)
广义二项式定理:
xx是实数,|x|<1|x|<1,uu 是实数,那么(1+x)u=∑k=0∞(uk)xk(1+x)u=∑k=0∞(ku)xk
其实这就是(1+x)u(1+x)u的幂级数展开,使用麦克劳林级数(即在x=0处泰勒展开)即可证明。
常用生成函数
这里给出一些最常用生成函数,以及其对应的序列一般项。(1). (1+ax)n=∑nk=0C(n,k)akxk(1+ax)n=∑k=0nC(n,k)akxk,ak=C(n,k)akak=C(n,k)ak,二项式定理得到
(2). 1−xr+11−x=∑nk=0xk1−xr+11−x=∑k=0nxk,ak=1,k⩽nak=1,k⩽n;否则为0,几何级数求和得到
(3). 11−ax=∑∞k=0akxk11−ax=∑k=0∞akxk,ak=akak=ak,对|x|<1|x|<1的几何级数求和取极限得到
(4). 1(1−x)2=∑∞k=0(k+1)xk1(1−x)2=∑k=0∞(k+1)xk,ak=k+1ak=k+1,对11−x11−x求导得到
(5). 1(1−x)n=∑∞k=0C(n+k−1,k)xk1(1−x)n=∑k=0∞C(n+k−1,k)xk,ak=C(n+k−1,k)=C(n+k−1,n−1)ak=C(n+k−1,k)=C(n+k−1,n−1),由广义二项式定理得到
(6). ex=∑∞k=0xkk!ex=∑k=0∞xkk!,ak=1/k!ak=1/k!,泰勒展开即可得到
(7). ln(1+x)=∑∞k=0(−1)k+1kxkln(1+x)=∑k=0∞(−1)k+1kxk,ak=(−1)k+1/kak=(−1)k+1/k,同上泰勒展开得到
生成函数可以用来求解计数问题,还可以用来求解递推关系和证明组合恒等式。这里不想写了,略过吧!(笑)
容斥原理及其应用
两个集合的容斥原理是很熟悉的,|A∪B|=|A|+|B|−|A∩B||A∪B|=|A|+|B|−|A∩B|,那么对于多个几个呢?很容易想到,但可能并不容易写出来。Inclusion–exclusion principle。容斥原理
设A1,A2....,AnA1,A2....,An是有穷集,则|A1∪A2∪⋯∪An|=∑1⩽i⩽n|Ai|−∑1⩽i<j⩽n|Ai∩Aj|+∑1⩽i<k<j⩽n|Ai∩Aj∩Ak|+⋯+(−1)n|A1∩A2∩⋯∩An||A1∪A2∪⋯∪An|=∑1⩽i⩽n|Ai|−∑1⩽i<j⩽n|Ai∩Aj|+∑1⩽i<k<j⩽n|Ai∩Aj∩Ak|+⋯+(−1)n|A1∩A2∩⋯∩An|可以看到加号和减号是交替出现的,保证了没有遗漏也没有重复。
三个集合的容斥原理:
应用很多,此处愉快地略过。
结语
其实我只想快速看完这本书,写完了之后,好好想一想应该怎样去写。还有慢慢肝算法导论,重新回顾数据结构,一堆技术书等着去肝呢!所有省略了很多内容,对自己还未掌握的东西抄上来就没有多大意义了。给了很多链接,但其实大部分链接我都未曾去认真看过(笑)。逐步积累,随性记录,知道自己要去的地方、要走的路,一直写着就好。——201.3.7
参考资料:《离散数学及其应用》(本科教学版,Kenneth H.Rosen著,原书第七版)
相关文章推荐
- 科学音频处理(三):如何使用 Octave 的高级数学技术处理音频文件
- 科学音频处理(三):如何使用 Octave 的高级数学技术处理音频文件
- 组合数学+错排问题【p4071】[SDOI2016]排列计数
- 高级正则表达式技术(Python版)
- 技术干货 | 如何选择上班路线最省时间?从A/B测试数学原理说起
- 高级纹理映射技术(6)
- 高等数学:第二章 导数与微分(2)初等函数 高级导数 隐函数 参数函数
- 深入理解PHP:高级技巧、面向对象与核心技术
- [转] 使用面向对象的技术创建高级 Web 应用程序
- JAVA技术:存储过程的基本的和高级特性
- 数学运算高级工具bc:小数精度;进制转换;计算平方及平方根
- Java Web编程的主要组件技术——Struts的高级功能
- php面试题之一——PHP核心技术(高级部分)
- 年度酷工作---高级数据工程师(公司靠谱,技术强悍,产品牛叉,福利有干货) 关键词:7000万用户、五星级厨师、住房补助 - V2EX
- Unp-高级i/o复用技术 读书笔记 (v0.3)
- 高级停靠(Dock)技术的实现
- 高级Bash脚本编程指南(31):数学计算命令
- 使用面向对象的技术创建高级 Web 应用程序
- .Net高级技术——字符串拘留池(Intern)
- Unity3D引擎之高级渲染技术