使用动态规划思想求解,即 dp[i][j] 表示将 i 个苹果放入到 j 个盘子的方法总数。
-
若 i<j,即苹果比盘子数小
- 比如将 2 个苹果放入 3 个盘子,必然会有一个盘子为空,即{0,x,y},其中一位固定为 0,不会影响最终的方案数,这和将 2 个苹果放入 2 个盘子的方案数目是一样的,即 {x,y}
- 因此有当 i<j 时,dp[i][j] = dp[i][i]
-
若 i>=j,即苹果数目不小于盘子数时,考虑是否有空盘子的情况(比如将 4 个苹果放入 3 个盘子)
- 若有空盘情况,相当于盘子数量少一个(因为固定一位是空盘,不会影响最终方案数目),即 {x,y,0},这对应着 dp[i][j-1]
- 若没有空盘的情况,对于 j 个盘子,相当于拿出来 j 个苹果,分配到每个盘子中1个,保证每个盘子分配到一个苹果。然后将剩下的 i-j 个苹果再分到 j 个盘子里,这对应着 dp[i−j][j]
- 因此有当 i>=j 时,dp[i][j] = dp[i][j-1] + dp[i−j][j]
-
边界条件
- 对于只有 1 个盘子的情况,分配方案只有 1 种,dp[i][1] = 1;
- 对于只有 0 个苹果的情况,分配方案只有 1 种,dp[0][j] = 1;
- 对于只有 1 个苹果的情况,分配方案只有 1 种,dp[1][j] = 1;
#include <iostream> #include <vector> #include <algorithm> using namespace std; int main(){ int m; int n; while (cin >> m) { cin >> n; vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0)); if (m == 0 || m == 1 || n == 1) { cout << 1; break; } // 边界条件 for (int i = 0 ; i <= m; i++) { dp[i][1] = 1; } for (int j = 0 ; j <= n; j++) { dp[0][j] = 1; dp[1][j] = 1; } for (int i = 2; i <= m; i++) { for (int j = 2; j <= n; j++) { if (i < j) { dp[i][j] = dp[i][i]; } else { dp[i][j] = dp[i][j - 1] + dp[i - j][j]; } } } cout << dp[m][n] <<endl; } }