ACM-5元和10元的经典问题

教学楼有一台奇怪的自动售货机,它只售卖一种饮料,单价5元,并且只收5元、10元面值的货币,但是同学们都很喜欢喝。这个售货机里没有多余的找零,也就是说如果一个持有10元的同学第一个购买,则他不能获得5元找零,但是如果在他之前有一个持有5元的同学买了这种饮料,则他可以获得5元找零。  假设售货机的货源无限,每人只买一罐,现在有N个持有5元的同学和M个持有10元的同学想要购买,问一共有多少种排队方法可以让每个持有10元的同学都获得找零。(这里的排队方法以某一位置上人持的钱数来分,即只要同一位置上的同学所持钱的数目相同,就算同一种排队方法)

输入:

多组测试数据   每组包含两个整数N,M(1<=M<=N<=1000),分别表示持有5元和10元的同学个数。

输出:

输出一个整数,表示排队方法总数。由于结果可能很大,所以结果需要模1000000007。

样例输入:

1 1

2 1

3 1

样例输出:

1

2

3


题目解答:

这是一个经典的问题,本来做的时候以为是卡特兰数的变形,后来发现并不是。这一个是逐点累加问题:

其实就是一个dp,dp[i][j]表示有i个人有5元,j个人有10元的排队方案数,我们可以发现:dp[i][0] = 1,因为大家都只有5元,怎么排都是一种方案

i < j时dp[i][j] = 0,因为有5元的人比有10元的少,必然会出现找不开的情况,那么此时方案数就是0不是以上两种情况时:dp[i][j]的方案数由dp[i - 1][j] + dp[i][j - 1]递推得到,考虑第m+n个人的状态

1.第m+n个人100,m+n-1里有m个50,n-1个100则dp[m][n-1]
2.第m+n个人50,m+n-1里有m-1个50,n个100则dp[m-1][n]

代码:

#include
using namespace std;
int MOD = 1000000007;
int dp[1005][1005];
int main()
{
	int i;
	memset(dp,0,sizeof(dp));  //整体赋值函数,将dp数组全部赋值为0
	for(i=0;i<=1000;i++)
		dp[i][0] = 1;            
	for(i=1;i<=1000;i++)
		for(int j=1;j<=i;j++)
			dp[i][j] = (dp[i][j-1]%MOD+dp[i-1][j]%MOD)%MOD;
	int n,m;
	while(scanf("%d%d",&n,&m)==2)
		printf("%d\n",dp[n][m]%MOD);
}



你可能感兴趣的:(数据结构&算法)