编程之美 4.3买票找零
问题:在一场球赛开始前,售票工作进行着,每张球票为50元。现在有2n个人排队购票,其中有n人手持50元,另外n人手持100元,假设开始售票是售票处没有零钱,问这2n个人有多少种排列方式,不至于售票出出现没钱找的情况?
解法一:
只要保证从队首开始往后数,任何时候,手持100的都比手持50的少,就肯定有钱找。
这里可以看出此问题类似括号匹配问题,用一个栈遍历排列看栈最后是否为空来检验排列是否合法。
设f(x)为求合法序列之个数的函数
若第一个左括号(位置为0)与第k(k=2i+1)个符号匹配,那么剩余括号的合法序列为:f(2i)*f(2n-2i-2)
f(0) = 1,可以用递归的方式求解,不过可以进一步推导出通项公式:
解法二:
设n-1个1和n+1个0组成的序列称为Sigma序列,这样的序列共有C(2n,n-1)个。
总序列数为C(2n,n),即合法序列和非法序列的总和。
假设存在某个(些)k,使前k项1的个数比0少一个,那么后面2n-k项中的1就比0多出一个。
将后面2n-k项的数01互换,那么整个序列就变成一个n-1个1和n+1个0的序列(即Sigma序列)
|--1:4 0:5--||--1:10 0:9--| =>01互换 |--1:4 0:5--||--1:9 0:10--| (这是我例举的一个例子,冒号后为相应的个数)
10的总个数变化为:1:14 0:14 =>1:13 0:15
这样就将非法序列对应到唯一一个Sigma序列。
下面的问题是Sigma序列能否唯一对应一个非法序列?
假设存在某个(些)k,使前k项1的个数比0少一个,那么后面2n-k项中的1就比0少出一个。(注意这里是少)
|--1:4 0:5--||--1:9 0:10--| =>01互换 |--1:4 0:5--||--1:10 0:9—|
10的总个数变化为:1:13 0:15 =>1:14 0:14
这样就将一个Sigma序列对应到唯一一个非法序列。
从而得出非法序列与Sigma序列一一对应,即非法序列的个数=Sigma序列的个数。
合法序列个数=C(2n,n)-C(2n,n-1)=C(2n,n)/(n+1)
下面说明一下容易误解的几个地方:
①Sigma序列是通过局部01互换转化成非法序列的,而不是非法序列==Sigma序列。它们之间只是对应关系不是相等的关系。
②Sigma序列只是假设由n-1个1和n+1个0组成的序列,至于叫什么序列自己喜欢。
总结:
此题是Catalan数典型的应用,类似的应用还有下面这些:
1.在圆上选择2n个点,将这些点成对连接起来使得所得到的n条线段不相交的方法数?
2.一位大城市的律师在她住所以北n个街区和以东n个街区处工作。每天她走2n个街区去上班。如果他
从不穿越(但可以碰到)从家到办公室的对角线,那么有多少条可能的道路?
3.一个栈(足够大)的进栈序列为1,2,3,..n,有多少个不同的出栈序列?
4.用n个长方形填充一个高度为n的阶梯状的方法个数?