第一次看这题的时候没有好好注意,后来发现这是一类大问题,学习了卡特兰数这个概念,顺便又复习了高中的排列组合知识、、、
先看一下书中引入卡特兰数的例子:
《编程之美》4.3买票找零:2n个人排队买票,其中n个人持50元,n个人持100元。每张票50元,且一人只买一张票。初始时售票处没有零钱找零。请问这2n个人一共有多少种排队顺序,不至于使售票处找不开钱?
分析1:队伍的序号标为0,1,…,2n-1,并把50元看作左括号,100元看作右括号,合法序列即括号能完成配对的序列。对于一个合法的序列,第0个一定是左括号,它必然与某个右括号配对,记其位置为k。那么从1到k-1、k+1到2n-1也分别是两个合法序列。那么,k必然是奇数(1到k-1一共有偶数个),设k=2i+1。那么剩余括号的合法序列数为f(2i)*f(2n-2i-2)个。取i=0到n-1累加即:
f(2n)=f(0)*f(2n-2)+f(2)*f(2n-4)+······+f(2n-4)*f(2)+f(2n-2)*f(0)
并且令f(0)=1,再由组合数C(0,0)=0,可得
以上就是一种卡特兰数的通项公式,下面具体介绍一下卡特兰数。
以下是百度百科中的定义:卡特兰数又称卡塔兰数,英文名Catalan number,是组合数学中一个常出现在各种计数问题中出现的数列。以比利时的数学家欧仁·查理·卡塔兰 (1814–1894)的名字来命名,其前几项为 : 1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440, 9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420, 24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452, …
我接触到的公式的定义有两种形式,一种是上面的f(2n),
f(2n)=f(0)*f(2n-2)+f(2)*f(2n-4)+······+f(2n-4)*f(2)+f(2n-2)*f(0)
还有一种就是下面的f(n)的
令f(0)=1,f(1)=1,catalan数满足递推式[1] :
f(n)= f(0)*f(n-1)+f(1)*f(n-2) + … + f(n-1)*f(0) (n>=2)
其实这两种只是表现形式不同,因为具体问题中,关键元素都是成对出现的,比如n对括号,总的个数就是2n个,所以一定要理解这两个个公式并结合具体问题具体分析。
也就是f(2n)=C(2n, n)/(n+1)
下面是证明过程
在<<计算机程序设计艺术>>,第三版,Donald E.Knuth著,苏运霖译,第一卷,508页,给出了证明:
问题大意是用S表示入栈,X表示出栈,那么合法的序列有多少个(S的个数为n)
显然有c(2n, n)个含S,X各n个的序列,剩下的是计算不允许的序列数(它包含正确个数的S和X,但是违背其它条件).
在任何不允许的序列中,定出使得X的个数超过S的个数的第一个X的位置.然后在导致并包括这个X的部分序列中,以
S代替所有的X并以X代表所有的S.结果是一个有(n+1)个S和(n-1)个X的序列.反过来,对一垢一种类型的每个序列,我们都能
逆转这个过程,而且找出导致它的前一种类型的不允许序列.例如XXSXSSSXXSSS必然来自SSXSXXXXXSSS.这个对应说明,不允许
的序列的个数是c(2n, n-1),因此
an = c(2n, n) - c(2n, n-1).[Comptes Rendus Acad.Sci.105(Paris, 1887), 436~437]
对于一个无限大的栈,一共n个元素,请问有几种合法的入栈出栈形式?
分析:n个元素出栈入栈操作共有2n个,且任何前x个操作中入栈操作必须不少于出栈操作,直接用f(2n)计算即可
P = a1 * a2 * a3 * … * an,其中ai是矩阵。根据乘法结合律,不改变矩阵的相互顺序,只用括号表示成对的乘积,试问一共有几种括号化方案?
分析:n个矩阵相乘需要n-1对括号,且任何前x个元素中”(”的个数一定大于”)”的个数,所以应该为f(2(n-1))
某个城市的某个居民,每天他须要走过2n个街区去上班(他在其住所以北n个街区和以东n个街区处工作)。如果他不跨越(但可以碰到)从家到办公室的对角线,那么有多少条可能的道路?
分析:其实也与括号问题相似,这个人一共要走2n步,其中向右与向上分别n步,那么,假设他第一步是向右的,那么之后的任何时刻,他向右的步数都不能少于想上的步数,即f(2n),当然,他也可以第一步时先向上,同样有f(2n)种走法,两者应该是以对角线对称的,所以答案为2*f(2n)。
在圆上选择2n个点,将这些点成对连接起来,且所得n条线段不相交,求可行的方法数。
分析:乍一看不能像上面三道题那样直接套公式。那么,先进行一下分析,将圆上的点依次标为P0,P1,…P2n-1。为了避免混淆,使用F(2n)表示2n个点可连成的线段数,选择Pk与P0相连(0< k< n)同样地可以看出,k必为奇数,否则1至k-1之间有奇数个点,不可能成对连成直线。同样地把k设为2i+1,那么线段P0Pk把剩余的点分为了1…2i和2i+2…2n-1,且新的连线不能与0k相交,它们只能属于0k把园划分出的这两个区域之一。即F(2n) = ∑F(2i)*F(2n-1-(2i+2)+1) = ∑F(2i)*F(2n-2i-2),其中i = 0 … n-1。这时,又转化成熟悉的形式了。
以上的应用中用到的公式都是f(2n),也可以发现他们有这如下几个特点:
n个结点可构造多少个不同的二叉树。(结点之间没有区别)
分析:这次并没有成对出现的元素了,n可以为奇数也可以为偶数,可以这样考虑:n个节点中肯定有一个根节点,剩下的n-1个节点可以这样分配T(0, n-1),T(1, n-2),…T(n-1, 0),其中T(i, j)中i,j表示左右子树的个数。
于是可以写出公式:f(n) = f(0)*f(n-1) + f(1)*f(n-2) + …….+ f(n-2)*f(1) + f(n-1)*f(0)
分析:以凸多边形的一边为基,设这条边的2个顶点为A和B。从剩余顶点中选1个,可以将凸多边形分成三个部分,中间是一个三角形,左右两边分别是两个凸多边形,然后求解左右两个凸多边形。
设n边形的解为h(n),那么h(n) = h(2)*h(n-1) + h(3)*h(n-2) + ……h(n-2)*h(3) + h(n-1)*h(2)。h(2)*h(n-1)表示三个相邻的顶点构成一个三角形,那么另外两个部分的顶点数分别为2和n-1。
设h(2) = 1,那么h(3) = 1, h(4) = 2, h(5) = 5。结合递推式,不难发现h(n) 等于f(n-2)。就是上面介绍的公式。
可以看出,这两道题和上面的稍微有些区别,用的公式是f(n)
还在网上找到一道笔试题
在一个2*n的格子中填入1到2n这些数值使得每个格子内的数值都比其右边和下边的所有数值都小的情况数;
12个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多少种?
分析:这2n个数选择n个在第一行,剩下的n个在第二行,并且每行都是从小到大排列。比如00001111就对应了1、2、3、4在第一行,5、6、7、8在第二行。为了使第一行比第二行对应位置小,换句话说,要保证序列合法,那么任何从第一个元素的开始的任意子序列中0的个数要大于等于1的个数。这就转化成了f(2n)。
参考链接:
1、从《编程之美》买票找零问题说起,娓娓道来卡特兰数——兼爬坑指南
2、Catalan数(卡特兰数)