【动态规划】01背包问题(装还是不装,老子不装啦。。。老子就是菜)

一、01背包问题是啥?

01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2至Wn,与之相对应的价值为P1,P2至Pn。01背包是背包问题中最简单的问题。01背包的约束条件是给定几种物品,每种物品有且只有一个,并且有权值和体积两个属性。在01背包问题中,因为每种物品只有一个,对于每个物品只需要考虑选与不选两种情况。如果不选择将其放入背包中,则不需要处理。如果选择将其放入背包中,由于不清楚之前放入的物品占据了多大的空间,需要枚举将这个物品放入背包后可能占据背包空间的所有情况。

二、如何理解01背包问题

01背包问题,在我看来就是一个装或不装的问题。为什么装?为什么不装?要以怎样的方法去装才能达到最优结果?面对各种价值不一,重量不一的物品,我们要做出最好的规划,使得背包的容量在可利用的范围内装下的物品总价值最大

三、如何解决01背包问题

一般用来解决01背包问题的算法思想都是动态规划,动态规划(Dynamic Programming,DP)是运筹学的一个分支,是求解决策过程最优化的过程。那么,我们具体应该如何实现呢?

首先我们应该对动态规划,有个初步的认识。动态规划就是将问题分成多个过程中的小问题,通过在每一个过程中对小问题的最优解决方法。一步步下来,直到最后一个过程得到结果,那么该结果就是这个问题的最优解决方法!

接下来,我们将这个认识应用到我们的01背包问题上。

第一,分阶段:如果有m个重量、价值不一的物品亟待考虑是否装进背包内,我们则分m个阶段。每一个阶段考虑一件物品是否应该装进背包内。那么,我们就已经将问题分成了m个小问题。但我们需要注意的是,m个小问题之间是有联系的,并且当前小问题的决策取决于上一个小问题得到的最优结果。

第二,m个小问题之间是有联系的,并且当前小问题的决策取决于上一个小问题得到的最优结果。:这个决策的行为是如何实现的呢?比如说,当前总容量为W1的背包所装下物品的总价值为V1。在背包总容量大于等于重量为W2、价值为V2的物品T的前提下,我们可以找到总容量只有W1-W2的背包,获取其在上一个阶段的总价值V3。我们通过比较(未装物品T时背包的总价值)和(腾出刚刚好的空间去装这个物品T时所得到的总价值),也即是比较(V1)和(V3+V2)。若是(V3+V2)要更大,则装!否则,则不装。

第三,总结公式:假如,对于一个最大容量为M公斤的背包,我们n件物品。因为根据上面我们的决策过程,我们需要获取0公斤到M公斤的不同最大容量的背包在不同阶段所能装下的物品最大价值和,同时,我们有n件物品则划分n个阶段,所以我们定义一个n+1行M+1列的二维数组。将决策过程抽象成给二维数组赋值,最后数组第n行第M列就是我们所求得最优结果。

根据第二步的决策步骤,结合到第三步中,我们可以得到如下决策公式:
在这里插入图片描述

四、用题目看01背包问题

在这里插入图片描述

我们可以利用简单的数组和动态规划算法得到如下示意表格:

在这里插入图片描述
核心代码:

     for(int i=1;i<=n;i++){
         for(int j=1;j<=M;j++){
             if(j>=W[i]){
             	 dp[i][j] = fmax(dp[i-1][j-W[i]]+C[i],dp[i-1][j]);
             }
             else dp[i][j] = dp[i-1][j];
         }
     }

五、01背包问题的解法优化

通过上面的分析,我们的思路是用一个二维数组去实现动态规划。但在上面的题目语境下,我们这种需要用到的只有二维数组的最后一个结果。而且考虑到动态规划的无后效性。每一个阶段依靠决策只需要用到上一个阶段,至于上上个阶段或者上上上个阶段都是完全用不到的了。那么我们就可以依靠这个特性去优化空间。接下来,我们只需要用到一个一维数组就可以替代二维数组。

每当我们决策到下一个阶段的时候,我们只需要从一维的dp数组最后一位开始往前刷新结果,依靠决策的是最后一位前面的未更新的数组元素(此时前面的数组元素因为未更新,所以还是上一阶段的决策结果),当本阶段的决策完成后,便是当前阶段的决策结果。所以,我们为什么换了一维数组之后,要从后往前决策,因为每一位的决策都需要依靠前面未更新的上一个阶段的决策结果。

核心代码:

     for(int i=n;i>=n;i++){
         for(int j=M;j>=W[i];j++){
             	 dp[j] = fmax(dp[j-W[i]]+C[i],dp[j]);
         }
     }

六、在LeetCode刷01背包

416. 分割等和子集
474. 一和零

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

peng_YuJun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值