题目描述:
某小学组织学生去公园玩,学生人数是M,门票是5元。其中N个孩子带的钱是5元,K个小孩带的钱是10元。老师没有零钱,问这些学生共有多少种排队方法,使得老师总能找开零钱。注意:两个拿五元钱的学生,他们的位置互换,算是一种新的排法。(M<10)
输入:
输入一行,M,N,K(其中M= N+K,M<=10)
输出:
输出一行,排队方案总数。
样例输入
4 2 2
样例输出
8
思路分析:
首先理解题目中总能找开的意思是,老师手里的5块可以找给10块的同学,这也就意味着第一位同学必须是5块,否则老师手里没钱,根本找不开。然后想一下可以怎么算排队方案,这里相同钱数的学生可以互换位置,此时就涉及到了排列组合的问题。但我们可以先不进行排列,最后再进行。因为每次找到一种组合时,只需要乘以N的阶乘再乘以K的阶乘,就时此种组合的全部排列情况。
因为人数不定,可以考虑采用递归的方式。此时就需要三个变量change表示此时老师手中可以找的零钱,num5,num10分别表示手中有5块和10块的人数,没交一个人,老师手中钱数会改变,相应人数也会改变。第一个同学给老师5块,那么change就需要加5,并且num5的人数减一,每当有同学交十块时,change就需要减5,num10也需要减一。
#include <iostream>
using namespace std;
int ways (int change, int num5, int num10)//三个变量分别存储老师手中可以找的零钱,拿着5块和10块同学的数量
{
//递归结束的终止条件
if (change < 0)//老师手中的钱不够找时,说明这种方法不行
{
return 0;
}
if (num5 == 0 && change < num10 * 5)
{
return 0;
}
if (num5 == 0 || num10 == 0)
{
return 1;
}
return ways(change + 5, num5 - 1, num10) + ways(change - 5, num5, num10 - 1);//两种情况,学生分别交了5块和10块
}
int factorial(int n)//阶乘
{
int res = 1;
for (int i = 1; i <= n; i ++)
{
res *= i;
}
return res;
}
int main()
{
int m,n,k;
cin >> m >> n >> k;
int cnt = ways(0,n,k);
cnt *= factorial(n) * factorial(k);
cout << cnt << endl;
system("pause");
return 0;
}
这个题的递归是正推通式,一般选取可以确定的一端开始推算递推式。
有问题欢迎在评论区打出,大家可以相互帮忙解决。