问题描述
例题:放苹果
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问公有多少种不同的分法?5,1,1和1,5,1是同一种分法
输入
第一行是测试数据数目t(0<=t<=20),以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10
输入
第一行是测试数据的数目t(0<=t<=20)。以下每行均包含两个整数M和N。以空格分开,1<=M,N<=10
对输入的每组数据M和N.用一行输出相应的K
样例输入
1
7 3
样例输出
8
算法思想
由于这里M和N的规模比较小,所以我们可以用递归来解决。递归算法里面有很多重复计算,我们得使用动态规划才能算
*设i个苹果放在k个盘子里方法总数是f(i,k),则:
由于我们盘子和苹果都是无差别的,我们可以考虑
当k>i时,f(I,k)=f(I,i)
k<=i时,总方法=有盘子为空的放法+没盘子为空的放法
f(I,k)=f(I,k-1)+f(i-k,k);
边界条件?
考虑到,现在要把i个苹果放在k个盘子里面,i>=k,当所有的盘子都不为空,此时,我们可以往所有的盘子里面放1个苹果,放完以后,还剩下i-k个,接下来就变成i-k个苹果放到k个盘子里的放法总数。
递归函数的终止条件
当m=0,即没有苹果要放的时候,表示苹果已经放完了,不往盘子里放苹果,盘子全为空,return 1。当n=0,即没有盘子要放了,此时return 0
注意,m和n的变化,防止m和n无法减到0,然后无穷递归,这里m不会减小到比0还小的数。
程序代码
#include<iostream>
using namespace std;
#define MAXSIZE 21
int layApple(int m,int n){
//将0个苹果放在n个盘中,有1种放法,即全部为空。
if(m==0){
return 1;
}
//将m个苹果放在0个盘子中,没有放法。
if(n==0){
return 0;
}
//将m个苹果放在n个盘子中,我们可以分情况讨论
//1.当m小于n时,即苹果数小于盘子数,由于苹果盘子均相同,所以m个苹果放在n个盘子中,相当于m个苹果放在m个盘子中
if(m<n){
return layApple(m,m);
}
//2.当m大于n时,即苹果数大于盘子数,这时候又可以将其分为两种情况,两种情况所产生的方法总和
//2.1.有盘子为空,则最少有1个盘子为空,那么方法总数等于将m个苹果放在n-1个盘子中
//2.2.没有盘子为空,则相当于每个盘子都放了一个,转化为m-n个苹果放在了n个盘子中。
else{
return layApple(m-n,n)+layApple(m,n-1);
}
}
int main(){
int m,n; //m个苹果放在n个盘子里
int *result=new int[MAXSIZE];
int t; //测试数据的数目
cin>>t;
for(int i=0;i<t;i++){
cin>>m>>n;
result[i]=layApple(m,n);
}
for(int i=0;i<t;i++){
cout<<result[i]<<endl;
}
return 0;
}