首先用递归的思想来思考这道题:
1,递归出口:当只有一个盘子或者 含有 0 个 或 1 个苹果的时候只有一种方法
2,当盘子数 n 大于苹果数 m 时,则必有 n - m 个空盘子,所以只需求 m 个盘子
放 m 个苹果时的方法数即可,
3,当盘子数 n 小于等于 苹果数 m 时,总方法数 = 当含有一个空盘子时的方法数
- 不含空盘子时的方法数。
原因:当在求只含有一个空盘子时的方法数时,已经包含了含有 2 ~ n - 1 个空盘子 的情况。
不含空盘子的计算:先将每个盘子装一个苹果,则问题变成了求 n 个盘子放 m - n
个苹果的方法数了。
其间,还可用记忆搜索优化(此处不再详讲)
然后用动态规划来优化代码:
新建一个动态规划表 dp;dp[i][j] 表示 i 个盘子放 j 个苹果的方法数。
则 当 i > j 时,dp[i][j] = dp[i - (i - j)][j] = dp[j][j](原因上面已经讲过)
当 i <= j 时,dp[i][j] = dp[i - 1][j] + dp[i][j - i];
最后dp[n][m] 就是所求。
#include <iostream>
using namespace std;
const int N = 21;
int dp[N][N];
int main(){
int m, n, k;
while(cin >> m >> n){
for(int i = 0; i <= m; i++){
for(int j = 1; j <= n; j++){
if(i == 0 || j == 1){
dp[i][j] = 1;
}else if(i < j){
dp[i][j] = dp[i][i];
}else{
dp[i][j] = dp[i][j-1] + dp[i-j][j];
}
}
}
printf("%d\n", dp[m][n]);
}
return 0;
}递归
#include <iostream>
using namespace std;
const int N = 21;
int func(int m, int n){
if(m == 0 || n == 1){
return 1;
}else if(m < n){
return func(m, m);
}else{
return func(m, n-1) + func(m-n, n);
}
}
int main(){
int m, n, k;
while(cin >> m >> n){
int ans = func(m, n);
printf("%d\n", ans);
}
return 0;
}
京公网安备 11010502036488号