OpenJudge 放苹果

本文详细介绍了如何使用递归和动态规划算法解决将一定数量的苹果放入多个盘子的问题,其中允许有盘子空着。通过递归思路分析,给出递归代码实现,并对比转化为动态规划的解决方案,最终展示动态规划代码。同时,针对空间优化进行了简要讨论。
摘要由CSDN通过智能技术生成

目录

放苹果

要求:

描述:

输入:

输出:

样例输入:

样例输出:

思路分析:

递归:

动态规划:

最终代码:

补充: 


放苹果

要求:

总时间限制: 1000ms

内存限制: 65536kB

描述:

 把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。

输入:

 第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10。

输出:

 对输入的每组数据M和N,用一行输出相应的K。

样例输入:

1
7 3

样例输出:

8

思路分析:

递归:

 这个题目难度不是很大,本质是求第二类Stirling数.由于题目中的M与N都较小,不一定非要使用动态规划,用递归也可以很好理解.我们在这里先给出递归的解法.

因为允许有的盘子空着不放,所以用M个苹果放入N个盘子,第一种可能是有盘子不放,第二种可能就是每个盘子都放.后者显然可以化归为M-N个苹果放入N个盘子的问题,而前者并不确定有几个盘子为空,如何处理?

对于有盘子不放的问题,虽然我们并不确定有几个盘子为空,但我们可以先讨论一个盘子为空,即将M个苹果放入N-1个盘子的问题.由于递归的性质,每一次递归都会减1,那么也就将盘子为空的所有情况都讨论到了.

所以递归的代码如下:

#include<iostream>
using namespace std;
static int K=0;
void Place(int M,int N){
    /* corner condition */
    if(N==1){
        K++; return;
    }
    Place(M,N-1);
    if(M>=N) Place(M-N,N);
}
int main(){
    int t;
    scanf("%d",&t);
    for(int i=0;i<t;i++){
        K=0;
        int M,N;
        scanf("%d%d",&M,&N);
        Place(M,N);
        printf("%d\n",K);
    }
}

动态规划:

其实将递归编写出来后,动态规划的方法也就差不多了。我们用一个dp[M][N]来存储M个苹果放入N个盘子的情况.那么根据上面的讨论就有dp[i][j]=dp[i][j-1]+dp[i-j][j].最后初始化一下dp[0]的这一行,我们就可以在循环输入之前将所有结果都算出来,每次输入后直接从dp数组中寻找对应结果即可.

最终代码:

#include<iostream>
using namespace std;
static int dp[11][11];
int main(){
    for(int i=1;i<11;i++){
        dp[0][i]=1;
    }
    for(int i=1;i<11;i++){
        for(int j=1;j<11;j++){
            dp[i][j]=dp[i][j-1]+(i>=j?dp[i-j][j]:0);//Judge whether i>=j
        }
    }
    int t;
    scanf("%d",&t);
    int M,N;
    for(int i=0;i<t;i++){
        K=0;
        scanf("%d%d",&M,&N);
        printf("%d\n",dp[M][N]);
    }
}

补充: 

其实还可以进一步优化空间,由于此题中dp数组本质是一个下三角矩阵,所以可以不用存储二维矩阵,一维数组来保存下三角的元素即可,但在此题中意义不大并且会使代码可读性变差,所以没有作此优化.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值