POJ 1664 放苹果

放苹果

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];

猜你喜欢

转载自blog.csdn.net/qq_35776409/article/details/107436285