分析:
设f(m,n)为m个苹果,n个盘子的放法数目,则先对n作讨论,
- 当n>m:则必定有n-m个盘子永远空着,去掉它们对摆放苹果方法数目不产生影响。即 if(n>m) f(m,n) = f(m,m)
- 当n<= m:
不同的放法可以分成两类:
- 含有0的方案数,不含有0的方案数 含有0的方案数,即有至少一个盘子空着,即相当于f(m,n)=f(m,n-1);
- 不含有0的方案数,即所有的盘子都有苹果,相当于可以从每个盘子中拿掉一个苹果,不影响不同放法的数目,即f(m,n)=f(m-n,n).而总的放苹果的放法数目等于两者的和,即 f(m,n)=f(m,n-1)+f(m-n,n)
- 递归出口条件说明:
- 当n=1时,所有苹果都必须放在一个盘子里,所以返回1;
- n = 0时, 没有苹果了,那就不放了,不放本身也是一种方法。(实际上是考虑到f(m-n, n),若n=0时设置值为0,则当n = m时,不留空盘子策略f(m-n, n) = 0,这就不对了)
代码:
#include <iostream>
#include <cstring>
using namespace std;
int dp[30][30]={0};
int fun(int m,int n){
if(dp[m][n]>0)
return dp[m][n];
int ans;
if(n==0||n==1||m==1)
ans = 1;
else if(m<n) //肯定有空盘子
ans = fun(m,m);
else //可能没有空盘子
ans = fun(m-n,n)+fun(m,n-1); //无空盘的情况+有空盘子的情况
dp[m][n]=ans;
return ans;
}
int main(){
int m,n;
while(scanf("%d %d",&m,&n)!=EOF){
cout<<fun(m,n)<<endl;
}
return 0;
}