放苹果
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 43882 Accepted: 26568
Description
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。
Input
第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10。
Output
对输入的每组数据M和N,用一行输出相应的K。
Sample Input
1
7 3
Sample Output
8
- 今天是暑假暑假回家的第一天,也是集训讲课开始 的第一天,但是由于赶路我并没有听课,晚上看了一点回放
- 今天第一天讲的是递归与回溯,第一个题讲的还能接受 后边的还没看
题目分析:
- 设f(m,n)表示m个苹果,同时放置在n个相同的盘子的分发数目,则:
- (1) 当m < n时 去掉m - n个空盘子不影响放置方法 return f(m ,n - 1);
- (2) 当m >= n 时,这时候可以分为两类考虑, 一是至少有一个盘子没有放置苹果,那么去掉这个空盘子还是不影响放置方法 即 : f(m,n) = f(m,n - 1) 二是当每个盘子都至少有一个苹果时,从每个盘子中都拿掉一个苹果 和原来的方式也是相同的 所以当n <= m时候 由加法原理,即: return f(m,n - 1) + f(m - n,n);
综上所述 如此看来本题应该是可以动态规划的 显然转移方程都已经给出
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int f(int m,int n) {
if(n == 1 || n == 0) return 1;
if(m < n) return f(m ,n - 1);// 其实 也可以写f(m,m) 原理是一样的 只不过运行快慢的原因
else return f(m,n - 1) + f(m - n,n);
}
int main(int argc,char * argv[]) {
int T; scanf("%d",&T);
while(T--) {
int n,m;
scanf("%d %d",&m,&n);
printf("%d\n",f(m,n));
}
return 0;
}
// 动态规划AC 代码
// 状态表示及转移方程基本同上
// 虽然这题数据范围很小 但是动态规划绝对是时间更优的
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int f[11][11];
int main(int argc,char * argv[]) {
int T; scanf("%d",&T);
for(int i=1; i<=10; i++) f[1][i] = f[0][i] = 1;
for(int i=2; i<=10; i++)
for(int j=1; j<=10; j++) {
if(i < j) f[i][j] = f[i][i];
else f[i][j] = f[i - j][j] + f[i][j - 1];
}
while(T--) {
int n,m;
scanf("%d %d",&m,&n);
printf("%d\n",f[m][n]);
}
return 0;
}
啊啊啊啊 写到这里 已经是我第三次修改这篇博客了
这个题又让我想起了记忆化搜索, 原来那个递归求解的过程跟搜索其实是差不多的,加上记忆化的思想(DP) 跑的更快,比动态规划更好理解。
就多一行代码
if(f[m][n]) return f[m][n];