【离散数学】高级计数技术

这是离散数学的第四篇,讨论高级计数技术。同步发布与个人博客,上一篇(【离散数学】计数/排列组合)讨论了计数以及排列组合,二项式定理等。但是仅凭排列组合等手段依然无法解决许多计数问题。这里首先讨论通过递推关系来求解计数问题,并介绍有递推关系引出的两个算法范式:动态规划和分治。这两种算法均是通过将问题分割为一系列的子问题来求解的,区别就是前者分割出来的子问题互相重叠,后者的子问题不重叠。这是两种很重要的算法,加上贪心、回溯、分支定界为五种很常用的算法。这里仅仅简单讨论思路,并分析其复杂度。关于具体的算法分析以及算法设计以后应该会讨论。而后介绍了求解一类很常见的特定递推关系——常系数线性齐次与非齐次递推关系的形式解法。并且还介绍了一种求解计数问题的很重要的手段——生成函数,这是幂级数的应用。最后介绍容斥原理,对,就是集合的容斥原理。以上内容以前均有涉及,这里再次探讨。


递推关系的应用

经典问题——汉诺塔

这是一个及其经典的问题,见汉诺塔(Tower of Hanoi),三根柱子,n个盘子,从上到下盘子从小到大。将所有n个盘子从一根柱子移动到另一根柱子,移动过程中小的盘子不能放在大的盘子下面。可以求解出所需要的最小步数,还可以编写算法打印出所有步数。
此处输入图片的描述
n=3的汉诺塔移动方法:
此处输入图片的描述

令移动n个盘子到另一个柱子所需最少次数为 H n ,考虑最下面一个最大的盘子,由于小的盘子不能放在大的盘子下面,所以必须首先将上面n-1个移动到另一个柱子,再将最下面的最大的一个移动到另一根柱子,再将n-1个移到其上,则完成了n个盘子的移动。则得到递推关系 H n = 2 H n 1 + 1 。初始条件很容易知道: H 0 = 0 H 1 = 1

求解递推关系:容易看出 H n + 1 = 2 ( H n 1 + 1 ) ,可以得到 H n = 2 n 1 。可以证明这便是移动n个盘子所需的最少次数。

卡特兰数

考虑一个在n+1个数 x 0 x 1 x 2 x n 的乘积中插入括号来规定乘法次序的方式数,令其为 C n
这里注意到一定会有一个乘法是在括号外面的(不需要加括号),假设其在 x k x k + 1 之间,则存在 C k C n k 1 种方式,考虑最后一个乘号可能取n个位置,则有

C n = k = 0 n 1 C k C n k 1

初始条件则为 C 0 = 1 C 1 = 1
利用生成函数的方法可以证明: C n = C ( 2 n , n ) n + 1 ,被称作第n个卡特兰(Catalan)数,序列 { C n } 被称为卡特兰数的序列。参见 OEIS A000108Catalan number - Wikipedia

动态规划与递推关系

动态规划(Dynamic programming,DP)是一种算法范式,遵循动态规划范式的算法是将原问题分解为更简单的重叠的子问题,通过子问题的求解来求解原问题。常用于求解最短路线、库存管理、资源分配、设备更新、排序、装载等问题。此类问题若用分治法来解,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。所以DP通过保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,从而降低复杂度。以后单独讨论,这里推荐阅读:动态规划解决01背包问题什么是动态规划?动态规划的意义是什么?


求解线性递推关系

这部分给人的感觉相当熟悉,在高等数学中有线性微分方程的求解,线性代数中有线性方程组的求解,与这里的线性递推关系的求解十分类似,可以说是如出一辙。

求解常系数线性齐次递推关系

一个常系数的 k 阶线性齐次递推关系指的是形如 a n = c 1 a n 1 + c 2 a n 2 + + c k a n k ,的递推关系,其中 c i 为实数, c k 0

为了求解 k 阶常系数线性齐次递推关系,这里的基本方法是寻找形如 a n = r n 的解,其中r是常数。递推关系要有形如 a n = r n 的解,则当且仅当 r 是方程

r k c 1 r k 1 c 2 r k 2 c k 1 r c k = 0
的解。
将上述方程称为该递推关系的 特征方程。方程的解称为 特征根。(与求解常系数线性微分方程如出一辙)。特征根有可能是复数,但这里仅考虑特征根为实数的情况。

定理:假设特征方程

r k c 1 r k 1 c k = 0
有k个不相等的根 r 1 , r 2 , . . . , r k 。那么递推关系 a n = c 1 a n 1 + c 2 a n 2 + + c k a n k 的解为
a n = α 1 r 1 n + α 2 r 2 n + + α k r k n

n N , α 1 , α 2 , . . . , α k 是常数。
另外,对其中的每一个特征根 r i ,如果并非一重而是 m i 重时,则用 ( α i , 0 + α i , 1 n + + α i , m i 1 n m i 1 ) r i n 替代 上述解中的 α i r i n 即可。

例:斐波那契数列(OEIS A000045
递推关系 f n = f n 1 + f n 2 ,初始条件 f 0 = 0 , f 1 = 1
特征方程 r 2 r 1 = 0 根为 r 1 = ( 1 + 5 ) / 2 r 2 = ( 1 5 ) / 2

f n = α 1 ( 1 + 5 2 ) n + α 2 ( 1 5 2 ) n
代入 f 0 , f 1 解出 α 1 = 1 5 α 2 = 1 5
则得到斐波那契数列的显式公式为
f n = 1 5 ( 1 + 5 2 ) n 1 5 ( 1 5 2 ) n

求解常系数线性非齐次递推关系

常系数线性非齐次递推关系:形如 a n = c 1 a n 1 + c 2 a n 2 + + c k a n k + F ( n ) ,与其相伴的齐次递推关系为 a n = c 1 a n 1 + c 2 a n 2 + + c k a n k ,很显然 通解 = 特解+齐次解

齐次解即对应的常系数线性齐次递推关系的解,记作 a n ( h ) ,特解记作 a n ( p )

不同形式的F(n)具有不同形式的特解

F ( n ) 特解形式
a n + b c n + d
α c n β c n

F ( n ) 形如 ( b t n t + b t 1 n t 1 + + b 1 n + b 0 ) s n .
则当 s 不是特征根时,特解形如 ( p t n t + p t 1 n t 1 + + p 1 n + p 0 ) s n .
s m 重特征根时,特解形如 n m ( p t n t + p t 1 n t 1 + + p 1 n + p 0 ) s n .


分治算法与递推关系

与动态规划相似,分治算法(Divide and conquer algorithm)范式也会将问题划分为一个或者多个小问题,不过这些小问题是不重叠的。连续使用这种划分直到可以快速找到这些小问题的解,然后将小问题的解合并为原问题的解。即三个步骤:分割原问题,解决子问题,合并得到最终解。常见简单分治算法:归并排序二分查找。这里将说明怎样用递关系来分析分治算法的复杂度。

分治递推关系

假设一个递归算法将规模为n的问题划分为a个子问题,每个子问题规模为n/b,并且需要g(n)的额外运算来合并这些子问题。用f(n)表示求解问题规模为n的问题所需运算数,则

f ( n ) = a f ( n / b ) + g ( n )

n = b k ,多次迭代后可以得到:

f ( n ) = a k f ( 1 ) + j = 0 k 1 a j g ( n / b j )

很容易知道,
二分查找的分治递推关系: f ( n ) = f ( n / 2 ) + 2
归并排序的分治递推关系: M ( n ) = 2 M ( n / 2 ) + n

分治算法的复杂度分析

定理1:设 f ( n ) 是满足 f ( n ) = a f ( n / b ) + c 的增函数, n b 整除, a 1
b 是大于1的整数, c 是正实数。那么

f ( n ) = { O ( n l o g b a ) a > 1 O ( log n ) a = 1
证明:令 n = b k 即可证得,当 n b k 时,依然成立。

很容易得出二分查找复杂度为 O ( log n )

主定理:若 f ( n ) = a f ( n / b ) + c n d ,则

f ( n ) = { O ( n d ) a < b d O ( n d log n ) a = b d O ( n l o g b a ) a b d

同理,令 n = b k 即可证得。(ps:上面的 表示大于号,但其实这个符号并不是这个意思。这里有一个bug,hexo自带一个功能的会把一段内连续的<>之间的内容注释掉,于是就只好将就一下。)

根据主定理,很容易得出归并排序复杂度为 O ( n log n )
可以看到,定理1只是主定理的特殊情况。
这里仅简单分析分治算法,并解决了其复杂度的问题,并未涉及分治算法的设计及具体实现。


生成函数

表示序列的一个有效方法是生成函数,把序列的项作为形式幂级数的变量x的幂的系数。可以用生成函数解决许多类型的计数问题。拓展阅读:Generating function - Wikipedia什么是生成函数? | Matrix67: The Aha Moments

定义

实数序列 a 0 , a 1 , . . . , a k , . . . 的(普通)生成函数是无穷级数

G ( x ) = k = 0 a k x k

例:序列 { C ( n , k ) } 的生成函数即是 G ( x ) = ( 1 + x ) n .

使用生成函数求解计数问题时,通常考虑形式幂级数,即不需要考虑其收敛域(对发散或收敛并不感兴趣)

广义二项式定理

广义二项式系数:
u 实数 k 为非负整数,广义二项式系数定义为

( k u ) = { u ( u 1 ) ( u k 1 ) / k ! k > 0 1 k = 0

当u为负整数时,展开即可有下列式子成立

( k n ) = ( 1 ) r C ( n + r 1 , r )

广义二项式定理:
x 是实数, | x | < 1 u 是实数,那么

( 1 + x ) u = k = 0 ( k u ) x k

其实这就是 ( 1 + x ) u 的幂级数展开,使用麦克劳林级数(即在x=0处泰勒展开)即可证明。

常用生成函数

这里给出一些最常用生成函数,以及其对应的序列一般项。

(1). ( 1 + a x ) n = k = 0 n C ( n , k ) a k x k a k = C ( n , k ) a k ,二项式定理得到
(2). 1 x r + 1 1 x = k = 0 n x k a k = 1 , k n ;否则为0,几何级数求和得到
(3). 1 1 a x = k = 0 a k x k a k = a k ,对 | x | < 1 的几何级数求和取极限得到
(4). 1 ( 1 x ) 2 = k = 0 ( k + 1 ) x k a k = k + 1 ,对 1 1 x 求导得到
(5). 1 ( 1 x ) n = k = 0 C ( n + k 1 , k ) x k a k = C ( n + k 1 , k ) = C ( n + k 1 , n 1 ) ,由广义二项式定理得到
(6). e x = k = 0 x k k ! a k = 1 / k ! ,泰勒展开即可得到
(7). ln ( 1 + x ) = k = 0 ( 1 ) k + 1 k x k a k = ( 1 ) k + 1 / k ,同上泰勒展开得到

生成函数可以用来求解计数问题,还可以用来求解递推关系和证明组合恒等式。这里不想写了,略过吧!(笑)


容斥原理及其应用

两个集合的容斥原理是很熟悉的, | A B | = | A | + | B | | A B | ,那么对于多个几个呢?很容易想到,但可能并不容易写出来。Inclusion–exclusion principle

容斥原理

A 1 , A 2 . . . . , A n 是有穷集,则

| A 1 A 2 A n | = 1 i n | A i | 1 i < j n | A i A j | + 1 i < k < j n | A i A j A k | + + ( 1 ) n | A 1 A 2 A n |

可以看到加号和减号是交替出现的,保证了没有遗漏也没有重复。

三个集合的容斥原理:
3
容斥

应用很多,此处愉快地略过。


结语

其实我只想快速看完这本书,写完了之后,好好想一想应该怎样去写。还有慢慢肝算法导论,重新回顾数据结构,一堆技术书等着去肝呢!所有省略了很多内容,对自己还未掌握的东西抄上来就没有多大意义了。给了很多链接,但其实大部分链接我都未曾去认真看过(笑)。

逐步积累,随性记录,知道自己要去的地方、要走的路,一直写着就好。——201.3.7


参考资料:《离散数学及其应用》(本科教学版,Kenneth H.Rosen著,原书第七版)

猜你喜欢

转载自blog.csdn.net/qq_35527032/article/details/79488584
今日推荐