题目描述
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法
输入
第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10。
输出
对输入的每组数据M和N,用一行输出相应的K。
样例输入
2
6 3
7 2
样例输出
7
4
思路
当n>m:必定有n-m个盘子永远空着,去掉它们对摆放苹果方法数目不产生影响。即dp(m,n)=dp(m,m)
当n<=m:不同的放法可以分成两类:
- 有至少一个盘子空着,即相当于
dp(m,n)=dp(m,n-1)
。按照动态规划或者递归的思路,dp(m,n-1)
已经包含dp(m,n-2)
的结果或者可以通过下一层的递归进行计算,所以这个只需要考虑最上层的dp(m,n-1)
即可。 - 所有盘子都有苹果,相当于可以从每种情况下的每个盘子中拿掉一个苹果,而不影响不同放法的数目(此处较难理解),即
f(m,n)=f(m-n,n)
而总的放苹果的放法数目等于两者的和,即dp(m,n)=dp(m,n-1)+dp(m-n,n)
边界:
- 当篮子数为1时,所有苹果都必须放在一个盘子里,方法数为1
- 当苹果数为0时,方法数为1
AC代码
#include<iostream>
#include<cstring>
using namespace std;
int main(){
int n,apple_num,basket_num;
cin>>n;
while(n--){
cin>>apple_num>>basket_num;
int dp[apple_num+1][basket_num+1];
memset(dp,0,sizeof(dp));
for(int i=1;i<=basket_num;i++) dp[0][i]=1;//边界
for(int i=0;i<=apple_num;i++) dp[i][1]=1;//边界
for(int i=1;i<=apple_num;i++)
for(int j=1;j<=basket_num;j++)
if(i>=j) dp[i][j]=dp[i][j-1]+dp[i-j][j];
else dp[i][j]=dp[i][i];
cout<<dp[apple_num][basket_num]<<endl;
}
return 0;
}