水题一道,但是感觉起来挺有意思的。
一场激烈足球赛即将开始,售票员紧张地卖票着……。
每张球票50元,现在有2n(1<=n<=18)个球迷排队购票,其中n个手持50元钞票,另外n个手持100元钞票。假设开始售票时售票处没有零钱可以找零。
问这2n个人有多少种排队方式,不至使售票处出现找不出零的局面?
例如当n=3时,共6人,3人持50元,3人持100元。可以找零的排队方式有如下5种:
50 50 50 100 100 100
50 50 100 100 50 100
50 50 100 50 100 100
50 100 50 50 100 100
50 100 50 100 50 100
输入格式
输入:
输入n,表示2n个球迷,其中n个手持50元,另外n个手持100元。
输出格式
输出:
2n个人,可以找零的排队方式数。
输入样例
3
输出样例
5
分析:
一开始天真地以为可以直接用高中的排列组合公式算(想想发现忘光了T_T),后来算了下才发觉不对劲。后面换了种想法。
Q1:假设抽屉里面没有钱,那么只能将一个50的排第一位。
Q2:假设抽屉有50元钱,那么这次可以随意排50或者100的在第一位。
问题可以抽象成,假设抽屉有money 的钱,有n1个人拿着50元,n2个人拿着100元待排队,求排队的方式数。开始是 money == 0, n1 == n2 == n。
很好的一个递归模型了,自顶向下,采用备忘录方法优化。
函数定义:
int GetCount(int n1, int n2, int money);
对于Q1:
count = GetCount(n1 - 1, n2, money + 50) ;
即抽屉没钱,只能先排一个50的在前面
对于Q2:
count = GetCount(n1 - 1, n2, money + 50) + GetCount(n1, n2-1, money-50);
即抽屉有钱的话,排序总数量是两种子问题的总和。
然后讨论问题的递归出口。
由上面分析可以看出,最终出口肯定是 n1 不断减少,直到0, money不断增加,增加到跟n2相等的情况。这种时候相当于,抽屉有 x 张50元,刚好有 x 个人拿着100元过来买票。那么很好理解,只有一种排队方法。
代码就不贴了。从来认为算法的代码没有可读性可言,看代码不如看分析。