首页 > 代码库 > 【组合数学】 03 - 母函数和递推关系
【组合数学】 03 - 母函数和递推关系
1. 母函数
1.1 母函数的定义
计数问题的结果一般可以表示为自然数集上的函数\(f(n)\),比如组合数\(\binom{n}{k}\)可以看成是关于\(k\)的函数。孤立的通项公式很难发现数值之间的内在联系,从而丢失了结果的整体性。本节介绍一下欧拉提出的母函数思想,它是计数问题的一个基本工具。
你一定知道组合数\(\binom{n}{k}\)其实是二项式\((1+x)^n\)的系数,换个角度想就是多项式\((1+x)^n\)中包含了整个数列\(\{\binom{n}{k}\}\)。利用单个对象来表示多个离散的对象,即方便了表示,也保留了离散对象的整体性,这对讨论想必是有好处的。为此对数列\(\{a_n\}\),称幂级数(1)为其母函数(gernerating function)。
\[g(x)=\sum_{k=0}^{\infty}a_kx^k=a_0+a_1x+a_2x^2+\cdots\tag{1}\]
这里并不要求幂级数收敛,我们只需把它当成是一种代数定义。和普通多项式一样,可以在上面定义类似的相等、加法、数乘、乘法(不考虑它们的现实意义),可以证明这样的代数构成了一个整环。在抽象代数中已经证明了,多项式有逆的充要条件是\(a_0\ne 0\)。比如常用的\(1+x+x^2+\cdots=\dfrac{1}{1-x}\),其中\(1-x\)就是前者的逆。
这里例子让我们想起了泰勒展开式,应该怎样看待一个初等函数与它的泰勒级数之间的关系?这些初等函数(比如\(\dfrac{1}{1-x}\))并不属于代数系统,但却可以作为对应幂级数的“缩写”形式存在。对于这些初等函数在复数域函数上的运算结果,它的幂级数是否与原代数系统的相同?多项式整环中的运算是兼容复数域多项式的,所以这两者可以看成是等价的,因此在使用时,大可放心地使用幂级数和初等函数。而这一点也为问题解决带来了便捷,正是母函数思想的威力所在。
1.2 母函数的应用
母函数除了作为一个形式表示,还能有做什么?代数系统中为什么要讨论加法、乘法?加法的意义不言而喻,一个计数问题被分为多个个独立的情况,在求得每个情况的母函数后,整个问题的母函数自然就是母函数之和。这其实就是大家在高中熟悉的加法原理,只不过母函数中包含了所有\(n\)的值。
还有一个就是所谓乘法原理:一个计数问题被分为多个步骤,每步的个数相乘便是整个计数值。乘法原理也可以用母函数表示,母函数相等后展开,其中的每一项就体现了乘法原理,当然合并同类项时就是加法原理。你可能已经发现,母函数乘法其实就是在帮你“自动”完成计数的“穷举法”,相比较技巧性强的方法,母函数更具一般性。
当然母函数也有应用场景的限制,问题的条件往往是多个变量的和为定值\(N\),而项\(a_kx^k\)表示变量取值\(k\)时有\(a_k\)种方法,母函数相乘后取项\(x^N\)的系数便是计数值。还拿二项式\(\binom{n}{k}\)为例,它表示从\(n\)个互异对象中选出\(k\)的个数。这里的变量就是每个对象被取的次数(只能是\(0,1\),母函数为\(1+x\)),条件是变量和为\(k\)。整个母函数是\((1+x)^n\),其中\(x^k\)的系数便是\(\binom{n}{k}\)。
值得注意的是\((1+x)^n\)中包含了所有\(k=0,1,\cdots,n\)的所有值,它们被做为一个整体保存了下了,之间的关系也更便于讨论(下一篇阐述)。关于母函数在计数问题中的应用,我们将在下一篇中有更多的例子,这里先就此打住。
• 求证:边长为正整数周长为\(k\)的三角形个数的母函数为\(T(x)=x^3(1-x)^{-1}(1-x^3)^{-1}(1-x^4)^{-1}\)。(提示:排序和差值)
2. 递推关系
2.1 递推关系的定义
有时候数列是以递推关系表达的,或者计数问题本身就适合用递推求解(比如经典的斐波那契数列\(f(n+2)=f(n+1)+f(n)\)),现在我们需要把递推式转化为显式表达式、或者表示出母函数。先来看定义,式(2)的所示的关系叫\(r\)阶递推关系,显然数列\(\{a_n\}\)由它的前\(r\)项唯一确定,这\(r\)项也称递推关系的初始条件。需要提醒的是,\(r\)阶的意思是\(a_n\)最多和\(r\)个前序数列相关,但并不一定每一项都与\(r\)个前序数列相关。反之,如果递推式不存在这样的有限整数\(r\),它被称为无穷阶递推关系。
\[a_n=F(a_{n-1},\cdots,a_{n-r},n)\tag{2}\]
举个简单的例子,大家都熟悉古老的汉诺塔(hanoi)游戏,把\(n\)个圆盘按从大到小的顺序放在一根柱子上,要求保持上小下大的关系将圆盘全部移到另一根柱子上。经过分析,最小的移动步骤是这样的:先设法将上面\(n-1\)个移动到第二根柱子,再将最大的盘移到第三根柱子,最后将那\(n-1\)个圆盘也移到第三根柱子。这个过程显然有递推式\(f(n)=2f(n-1)+1\),求解就很简单了。得到递推关系也许并不是一件容易的事,但这里我们不关心这一步,假定已经获得了递推式表达式,注意力集中在求解上。
2.2 线性递推关系
递推关系式千变万化,不可能有统一的解法,具体问题需要具体分析,大部分形式都不一定能求解。这里我们只研究几种常见递推式,并试图寻找各自一般的解法。首先比较简单的是一阶阶线性递推关系(3),为了消除首项系数,设\(\prod\limits_{k=0}^na(k)=A(n)\),并设\(u‘_n=\dfrac{u_n}{A(n)}\),则有\(u‘_n=u‘_{n-1}+b(n)/A(n)\)。\(u‘_n\)比较容易求得,最后得到\(u_n\),这里就不展开了。特别地,当\(a(n),b(n)\)为常数时,可以得到\(u_n\)通项式(4),汉诺塔问题便可求解。
\[u_n=a(n)u_{n-1}+b(n)\tag{3}\]
\[u_n=au_{n-1}+b\;\Rightarrow \;u_n=\dfrac{1-a^n}{1-a}b+a^nu_0\tag{4}\]
当线性递推关系上升到\(r\)时,情况变得复杂,我们不妨从最简单的齐次线性常系数递推关系(式(5))看起。将递推关系的每个表达式按列写成矩阵(6),观察矩阵的每一行,它们含有完整的数列(除开始有限项)。这就启发我们把数列当整体看待,自然想到用母函数\(U(x)=\sum\limits_{k=0}^{\infty}u_kx^k\),为方便讨论,这里先假设\(u(x)\)有正的收敛域,后面得到表达式再回头验证。
\[u_n=\sum_{i=1}^rc_iu_{n-i}\tag{5}\]
\[\begin{matrix}u_r&u_{r+1}&\cdots&u_n&\cdots\\c_1u_{r-1}&c_1u_r&\cdots&c_1u_{n-1}&\cdots\\c_2u_{r-2}&c_2u_{r-1}&\cdots&c_2u_{n-2}&\cdots\\\vdots&\vdots&\ddots&\vdots&\cdots\\c_ru_0&c_ru_1&\cdots&c_ru_{n-r}&\cdots\end{matrix}\tag{6}\]
因为第一行的母函数是其它行之和,综合考察每行母函数与\(U(x)\)的差别,不难得到\(U(x)=U(x)\sum\limits_{k=1}^rc_kx^k+h(x)\),从而有式(7)。记\(c(x)\)为式(8),其中\(\alpha_k\)是\(c(x)\)的互异复根,它被称为递推式(5)的特征多项式。则易知式(7)的分母为\((1-\alpha_1x)^{e_1}\cdots(1-\alpha_sx)^{e_s}\),利用有理分式的知识可知,式(7)可以拆分为若干项\(\dfrac{\beta_{ij}}{(1-\alpha_ix)^j}\)之和(\(\beta_{ij}\)为常数)。再利用\((1-\alpha x)^{-k}\)的泰勒展开式\(\sum\binom{n+k-1}{k-1}\alpha^kx^k\),容易知道\(x^n\)项的系数为\(\sum\limits_{k=1}^sp_k(n)\alpha_k^n\),其中\(p_k(x)\)阶为\(e_k-1\)。
\[U(x)=\dfrac{h(x)}{1-c_1x-\cdots-c_rx^r},\;\text{deg}\,(h(x))<r\tag{7}\]
\[c(x)=x^r-c_1x^{r-1}-\cdots-c_r=(x-\alpha_1)^{e_1}\cdots(x-\alpha_s)^{e_s}\tag{8}\]
这其实就得到了\(u_n\)的表达式(9),每个\(p_k(n)\)含有\(e_k\)个待定系数,总共正好有\(r\)个待定数,而它们可以有\(r\)个初始条件确定。斐波那契数列的递推式\(f(n)=f(n-1)+f(n-2)\)就是典型的齐次递推关系,它的特征方程是\(x^2-x-1\),两个根为\(\alpha_{1,2}=(1\pm\sqrt{5})/2\),将\(f(0)=f(1)=1\)带入\(f(n)=p_1\alpha_1+p_2\alpha_2\)便得到斐波那契数列的通项公式(10)。
\[u_n=p_1(n)\alpha_1^n+p_2(n)\alpha_2^n+\cdots+p_s(n)\alpha_s^n,\;\text{deg}\,(p_k(x))=e^k-1\tag{9}\]
\[f(n)=f(n-1)+f(n-2),\,f(0)=f(1)=1\;\Rightarrow\;f(n)=\dfrac{1}{\sqrt{5}}(\alpha_1^{n+1}+\alpha_2^{n+1})\tag{10}\]
再来看线性常系数递推关系式(11),在给定初始条件时,它也有唯一解\(u_n\)。对于这样的问题,先忽略初始条件说不定可以降低一些难度,针对递推式(11)的特点,说不定可以“目测”出一个解\(u‘_n\)。注意到\(u_n-u‘_n\)满足齐次递推式(5),故它们的解正好相差一个式(5)的解(两个初始条件的差作为式(5)的初始条件)。某个初始条件下式(11)的解\(u‘\)被称为特解,它的通解则是式(12)。
\[u_n=\sum_{i=1}^rc_iu_{n-i}+g(n)\tag{11}\]
\[u_n=u‘_n+\sum_{k=1}^sp_k(n)\alpha_k\tag{12}\]
2.3 卷积递推关系
最后来看一个虽然复杂但却极为常用的递推关系,先来看一个问题:将\(n\)个\((\)和\(n\)个\()\)排列开来,有多少中排法使得序列有意义?有意义是指:(1)一对括号\(()\)是有意义的;(2)如果序列\(A,B\)有意义,那么\(AB\)和\((A)\)也有意义。记有意义的排列数为\(C_n\),其中\(C_0=C_1=1\)。第一个显然是\((\),先找到和它配对的\()\),则序列可以表示为\((A)B\)。要使得排列有意义,必须\(A,B\)都有意义,故容易有递推式(13)。
\[C_n=C_0C_{n-1}+C_1C_{n-2}+\cdots+C_{n-1}C_0,\;\;C_0=C_1=1\tag{13}\]
满足递推关系(13)的数列被称为卡特兰(Catalan)数列,这个递归关系会出现在许多问题中,这里再列举几个例子,推导思路非常相似(二分和递归),这里就不赘述了。
(1)乘法组合问题。对于乘法\(x_0x_1\cdots x_n\),添加括号使其形成不同的乘法顺序。
(2)进出栈序列。\(n\)个数依次进栈,中途可以有数出栈,求进、出栈序列的个数。
(3)找钱问题。\(n\)个人拿5元、\(n\)个人拿10元排队买5元的东西,如何排队使得不需要提前准备零钱。
(4)数列个数问题:正整数列\(a_1\leqslant a_2\leqslant\cdots\leqslant a_n\),其中\(a_k\leqslant k\)。
(5)凸多边形的三角形分割。\(n+2\)边凸多变形可以被\(n-1\)条不交叉的对角线分成\(n\)个三角形,讨论某一条边被划分的情况。
(6)Dyck路计数。从格点\((0,0)\)走到\((2n,0)\),每步只能走向右上或右下方向最近的格点,且不能到达\(x\)轴下方。
对于和式\(S=\sum\limits_{k=0}^nx^ky^{n-k}\),在数学中非常常见,比如说级数相乘的柯西乘积。\(S\)往往被称为向量\((x_0,x_1\cdots,x_n)\)和\((y_0,y_1\cdots,y_n)\)的卷积(Convolution,或柯西乘积),它是向量乘积的一种定义。回顾级数的柯西乘积,我们觉得这里用母函数处理也许会比较好。为此设卡特兰数列的母函数为\(C(x)\),还是先假定它有正收敛域。
利用级数的柯西乘积,容易有\(C(x)C(x)=(C(x)-1)/x\),解得\(C(x)=\dfrac{1\pm\sqrt{1-4x}}{2x}\)。展开\(C(x)\)的幂级数,并根据数列为正可得到卡特兰数列(14)。
\[C_n=\dfrac{1}{n+1}\binom{2n}{n}\tag{14}\]
上面两个例子充分展示了母函数在求解递推关系中的威力,观察递推关系的特点,列出母函数的方程,便可以很快得到母函数,更甚者可以得到数列通项。请尝试解决以下二元递推关系:
• \(\left\{\begin{matrix}a_{n+1}-a_n+b_n=n\\a_n+2b_{n+1}-b_n=2\end{matrix}\right.\),已知\(a_0,b_0\)。
【组合数学】 03 - 母函数和递推关系