【DP算法篇之初学】背包问题

本文通过介绍01背包问题,探讨动态规划在背包问题中的应用。作者通过详细解析01背包、完全背包的算法思想,阐述了如何优化空间复杂度,并提供了相关编程题的解题思路和代码实现。
摘要由CSDN通过智能技术生成
               

昨天做了爱奇艺的内推笔试,编程题又出现了动态规划问题,感觉动态规划出现的概率好大,需要加强下。这里借用背包问题开始我们的学习。


背包问题的经典讲解可以参见背包问题九讲,此外我在刷题的过程中发现还发现了背包六问





0 1 背包


最经典的 01 背包问题可以描述为:

有n个物品,每个物品的重量为w[i],每个物品的价值为v[i]。现在有一个背包,它所能容纳的重量为W,问:当你面对这么多有价值的物品时,你的背包所能带走的最大价值是多少?


思路:每个物品无非是装入背包或者不装入背包,那么就一个一个物品陆续放入背包中。

我们用c[i][w]表示处理到第i 个物品时背包容量为w下所能装下的最大价值。关键的状态转移方程如下:



伪代码如下:




优化空间复杂度


以上方法的时间和空间复杂度均为O(Wn),其中时间复杂度应该已经不能再优化了,但空间复杂度却可以优化到O(W)。


先考虑上面讲的基本思路如何实现,肯定是有一个主循环i = 1..n,每次算出来二维数组 c[i][0..W] 的所有值。那么,如果只用一个数

组c[0..W],能不能保证第 i 次循环结束后 c[w] 中表示的就是我们定义的状态 c[i][w] 呢? c[i][w] 是由 c[i - 1][w] 和 c[i-1][w - c[i]] 两个

子问题递推而来,能否保证在推 c[i][w] 时(也即在第 i 次主循环中推 c[w] 时)能够得到 c[i - 1][w] 和 c[i - 1][w - c[i]] 的值呢?事实

上,这要求在每次主循环中我们以 w=W..0的顺序推 c[w],这样才能保证推 c[w] 时 c[w - c[i]] 保存的是状态 c[i - 1][w - c[i]] 的值。伪

代码如下:

for i = 1..n    for w = W..0        c[w] = max{c[w], c[w - w[i]] + v[i]};

其中的 c[v] = max{c[w], c[w - c[i]]}一句恰就相当于我们的转移方程 c[i][w] = max{c[i - 1][w], c[i - 1][w - c[i]]},因为现在的 c[w - c[i]]就

相当于原来的 c[i - 1][w - c[i]]。如果将 v 的循环顺序从上面的逆序改成顺序的话,那么则成了 c[i][w] 由 c[i][w - c[i]] 推知,与本题意不

符,但它却是完全背包问题最简捷的解决方案,故学习只用一维数组解01背包问题是十分必要的。


事实上,使用一维数组解01背包的程序在后面会被多次用到,所以这里抽象出一个处理一件01背包中的物品过程,以后的代码中直接调用不加说明。

过程ZeroOnePack,表示处理一件01背包中的物品,两个参数weight、value分别表明这件物品的重量和价值。

procedure ZeroOnePack(weight, value)    for w = W..weight        c[w] = max{c[w], c[w - weight] + value}</
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值