动态规划——划分数问题

例题——放苹果

        我自己读完题开始想思路时,边界条件能考虑到,并且也考虑到如果过盘子的数量大于苹果的数量,那么这种情况的放置方法总数与“盘子数量等于苹果数量”是相等的。

        不过真的是没想出来最核心的状态转移方程,虽然代码通过了牛客网的在线测试,但是这个代码的复杂度比真正标准的状态转移要高,应该是有些冗余计算。

自己写的代码

#include <iostream>
using namespace std;
int main(){
    int dp[11][11];
    for(int i=1;i<=10;i++)
        dp[i][1]=1;
    for(int j=0;j<=10;j++)
        dp[0][j]=1;
    for(int j=2;j<=10;j++){
        for(int i=1;i<=10;i++){
            if(i<j){   // 盘子的数量大于苹果的数量
                dp[i][j] = dp[i][i];
            }else{   // 分别考虑每个盘子最少放k个苹果的情况,然后求和
                int sum=0;
                for(int k=0;k<=i/j;k++){
                    sum+=dp[i-k*j][j-1];
                }
                dp[i][j] = sum;
            }
        }
    }
    int N,M;
    while(cin>>M>>N){
        cout<<dp[M][N]<<endl;
    }
    return 0;
}

基础知识——划分数问题

问题描述

  • 划分数问题:有n个无区别的物品,将它们划分成不超过m组,求出划分方法数。
  • 放苹果问题:把n个同样的苹果放在m个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?

解题思路——以"放苹果"为例

        放苹果的问题乍看之下很复杂,盘子是一样的,苹果也是一样的;只要每个盘子里面放的苹果是一样多的,不管顺序如何最终得到的都是同一种分法。其实我们需要把问题简化。就拿这个放苹果的问题而言,我们只需要分两种情况:有空盘子和没空盘子

  • 有空盘子:f(n, m) = f(n, m-1)    //   先让一个盘子空着,还有m-1个盘子,剩下的问题就是吧这n个苹果放到m-1个盘子里的问题
  • 没有空盘子:f(n, m) = f(n-m, m)    //  没有空盘子,我们可以看成先给每一个盘子放一个苹果,则还剩下n-m个苹果,剩下的问题就是把这n-m个苹果放到m个盘子里的问题了

        因此:f(n, m) = f(n, m-1) + f(n-m, m)   ( n>=m)

        上面的表达式并不完整,当n<m时的情况没有考虑,当n<m的时候,f(n, m)=f(n, n)

        递推一般都要有边界,稍微看一下就能找到,当只有一个盘子时明显只有一种方法,另外没有苹果和只有一个苹果的时候也只有一种放法。即当m=1或者n=0时,f(n, m) = 1

        综上:

  • f(n, m) = 1  (m=1,n=0)
  • f(n, m) = f(n, n)   (n<m)
  • f(n, m) = f(n, m-1) + f(n-m, m)   ( n>=m) 

代码

#include <iostream>
using namespace std;
int main(){
    int dp[11][11];
    for(int i=1;i<=10;i++)
        dp[i][1]=1;
    for(int j=0;j<=10;j++)
        dp[0][j]=1;
    for(int j=2;j<=10;j++){
        for(int i=1;i<=10;i++){
            if(i<j){
                dp[i][j] = dp[i][i];
            }else{
                dp[i][j] = dp[i][j-1]+dp[i-j][j];
            }
        }
    }
    int N,M;
    while(cin>>M>>N){
        cout<<dp[M][N]<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值