思路:
第一次尝试(错误):将M个苹果转换成为不同重量堆的苹果,使用0-1背包解决,失败:原因是在苹果分堆在聚合过程后无法控制总数恰好等于M;

第二次尝试(错误):注意到M个苹果放到N个盘子里,依次相加空出0个、1个……N个盘子各个数量,失败;原因是调用M个苹果装到N-k个盘子会有重复:例如将(M=4,N=3)时,4个苹果分别放入3个、2个、1个盘子时分别结果为1,3,1,会有重复因为放入2个盘子的(0,4)放法和放入一个盘子相同。

第三次尝试(成功):令f(n,m)表示n个盘子盛放m个苹果,注意到拿n-1个盘子(可以有空盘子)放m个苹果和n个盘子(无空盘子)放m个苹果无重复
所有有 子问题1:f(n,m)[容许有空盘子] = f(n-1,m)[容许有空盘子] + f(n,m)[无空盘子]
而什么时候n个盘子放m个苹果没有空盘子呢,就是n个盘子每个至少放一个:
所以有 子问题2: f(n,m)[无空盘子] = f(n,m-n) [容许有空盘子]
可以得到转移方程:f(n,m)[容许有空盘子] = f(n-1,m)[容许有空盘子] +f(n,m-n) [容许有空盘子];
也就是f(n,m) = f(n-1,m)+f(n,m-n);
注意边界条件 : f(0,0) = 1;
f(0,k) = 0 , k!=0
以下给出递归和动态规划两种解决办法,请诸君参考:

#include <iostream>
using namespace std;
// 递归求解
// int f(int n,int m) 
// {
//     if(n == 0 && m == 0) return 1;
//     else if(n == 0 && m != 0) return 0;
//     else if( m >= n) return f(n-1,m)+f(n,m-n);
//     else return f(m,m);
// }

// 动态规划求解
int dp[11][11];
void Initial()
{
    for(int i = 0;i<=10;i++)
    {
        for(int j = 0;j<=10;j++)
        {
            // i=0的初始化可以放到循环外面写,这样在循环时可以减少判断次数
            if(i == 0 && j == 0) dp[i][j] = 1;
            else if(i == 0 && j != 0) dp[i][j] = 0;
            // 盘子数少的时候,空出m-n个盘子,转化成m个盘子盛放m个苹果
            else if(i > j) dp[i][j] = dp[j][j]; 
            else dp[i][j] = dp[i-1][j] + dp[i][j-i]; // 状态转移方程
        }
    }
}
int main()
{
    int m,n;
    Initial();
    while(cin >> m >> n)
    {
        cout << dp[n][m] << endl;
    }
}