题目描述
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。
输入描述:
每行均包含二个整数M和N,以空格分开。1<=M,N<=10。
输出描述:
对输入的每组数据M和N,用一行输出相应的K。
思路:假设有7个苹果,3个盘子。
那么可以这样尝试这样划分: 0+ 7 (只用了一个盘子)
1+ 6 (用了两个盘子)
2+ 5 (用了两个盘子)
3+ 4 (用了两个盘子)
现在思考,如果用3个盘子,有哪些划分方法?
考虑将(1+6)在进行划分,即将装有6个苹果的盘子,分出一部分。可以有 1+5,2+4,3+3
即(1,1,5),(1,2,4),(1,3,3)。其实从这里我们可以找到一些动态规划的思路,如果我们已经计算出将6个苹果装在两个盘子,有多少种方法,那么,就可以很快的得出,将7个苹果分成3盘,其中1盘有1个的方法数。
同理,也可以继续分析(2+5).....
设dp[i][j]为i个苹果,放入j个盘子(其中可以有盘子为空)的方法数。
1. dp[0][j] =1 (因为已经没有苹果了)
2. 如果n>m,那么其实只要计算dp[m][m]即可,因为肯定有盘子空着
3. dp[i][j]= dp[i-j][j] + dp[i][j-1] (它的意思是:如果我有i个苹果,j个盘子。那么我可以这么选,要么把每一个盘子都至少放一个,即先拿出j个苹果。要么我空着一些盘子(其实你空着1个盘子,这样递归下去,就可以实现空着多个盘子。))
代码:
记忆化搜索或者递推都可以
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+7;
int dp[20][20];
int dfs(int m,int n)
{
if(m==0) return 1;
if(n==1) return 1;
if(dp[m][n]!=-1) return dp[m][n];
if(n>m) return dp[m][n]=dfs(m,m);
return dp[m][n] = dfs(m-n,n)+dfs(m,n-1);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int m,n;
while(scanf("%d%d",&m,&n)!=EOF)
{
memset(dp,-1,sizeof(dp));
cout<<dfs(m,n)<<endl;
}
return 0;
}