笔试算法学习--买票找零问题(卡特兰数)

问题:2n个人排队买票,其中n个人持50元,n个人持100元。每张票50元,且一人只买一张票。初始时售票处没有零钱找零。请问这2n个人一共有多少种排队顺序,不至于使售票处找不开钱?

题目另一种形式:有n对左括号和右括号,现在问到底有多少中括号合法匹配的组合?


解:

原理

实际上,这个就是卡特兰数的一个应用:

其前几项为 : 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, …

令h(0)=1,h(1)=1,catalan数满足递推式:

h(n)= h(0)*h(n-1)+h(1)*h(n-2) + … + h(n-1)h(0) (n>=2)

例如:

h(2)=h(0)*h(1)+h(1)*h(0)=1*1+1*1=2 
h(3)=h(0)*h(2)+h(1)*h(1)+h(2)*h(0)=1*2+1*1+2*1=5

另类递推式[2] :

h(n)=h(n-1)*(4*n-2)/(n+1);

递推关系的解为:

h(n)=C(2n,n)/(n+1) (n=0,1,2,…)

递推关系的另类解为:

h(n)=c(2n,n)-c(2n,n-1)(n=0,1,2,…)


我们现在就应用h(n)=C(2n,n)/(n+1)(n=0,1,2,...) 求解我们的找零问题(括号匹配问题)。

我们把右括号设为状态‘1’,左括号设为状态‘0’。2n个数的排序对应n个1和n个0组成的2n位二进制数。当一个右括号参与到匹配当中时,我需要保证这个右括号之前的括号序列当中至少有一个悬空的左括号,因此可行解的总数目等于由左而右扫描由n个1和n个0组成的2n位二进制数,在这个扫描过程当中1的累计数不小于0的累计数的方案种数。

在2n位二进制数中填入n个1的方案数为c(2n,n)(位置在1被确定以后,0的位置会被自动确定)。在这些c(2n,n)个方案中减去不符合要求(由左而右扫描,在这个扫描过程当中0的累计数大于1的累计数)的方案数目,随即我们得到了最后的解。

不符合要求的解的特征是由左而右扫描时,必然在某一奇数位2m+1位上首先出现m个0的累计数和m+1个1的累计数(又前提条件下,有m个0,m个1,故可知,接下来的序列当中还能找到n-m个0和n-m-1个1),如若把这2m+1位上的0和1互换,使之成为m+1个0和m个1,结果得1个由n+1个0和n-1个1组成的2n位数,即一个不合要求的数对应于一个由n+1个0和n-1个1组成的排列。

反过来,任何一个由n+1个0和n-1个1组成的2n位二进制数,由于0的个数多2个,2n为偶数,故必在某一个奇数位上出现0的累计数超过1的累计数。同样在前面部分0和1互换,使之成为由n个0和n个1组成的2n位数,即n+1个0和n-1个1组成的2n位数必对应一个不符合要求的数。

因而不合要求的2n位数与n+1个0,n-1个1组成的排列一一对应。

显然,不符合要求的方案数为c(2n,n+1)。由此得出输出序列的总数目= c(2n,n) - c(2n,n+1) = c(2n,n) / (n+1) = h(n)。


你可能感兴趣的:(笔试算法学习)