背包问题(01背包+滚动数组+完全背包)
0|101背包
定义:在件物品取出若干件放在空间为的背包里,每件物品的体积为,至,与之相对应的价值为,至。
01背包的约束条件是给定几种物品,每种物品有且只有一个,并且有权值和体积两个属性。
在01背包问题中,因为每种物品只有一个,对于每个物品只需要考虑选与不选两种情况。
(故称为01背包。)
解决这个问题我们需要从前一个状态递推到下一个状态,最终递推到我们想要的状态。
01背包题目的雏形是:
有件物品和一个容量为的背包。第件物品的体积是,价值是。求解将哪些物品装入背包可使价值总和最大。
这个问题核心的矛盾有两处:1.背包的容量,2.所装物品的价值。
所以,我们不妨假设背包内物品的价值为 。($ I C$是它的体积)
阶段:前 件物品中,已经选取若干件物品放在背包中
状态:前 件物品,选取若干件物品放入所剩空间为W的背包中的所能获得的最大价值
决策:第 件物品放或者不放
由此,其状态转移方程为:
理解:对于第 件物品,要么不放背包:;要么就放入背包:。
(放入背包,就是 的体积,然后价值 。)
代码如下:
优化:滚动素组
滚动数组是一种能够在动态规划中降低空间复杂度的方法。
有时某些二维dp方程可以直接降阶到一维,在某些题目中甚至可以降低时间复杂度,是一种极为巧妙的思想。
简要来说,就是通过观察dp方程来判断需要使用哪些数据,可以抛弃哪些数据。
一旦找到关系,就可以用新的数据不断覆盖旧的数据量来减少空间的使用。
从而实现“滚动”。
例:
让 , 不断的更新迭代,从而完成斐波那契数列的计算。
在01背包中,问题核心的矛盾有两处:1.背包的容量,2.所装物品的价值。
那么对于物品的序号,便是一个可以抛弃的数据。
我们让$ f[i]f[i-1]$上。
(就是表格法只用一层表格。)
这时我们的函数只有一个参数。
也就是说我们在每次遍历时,背包里面刚开始存的是上一个状态的,核心代码变成了这样:
像之前那样的思考:
如果 之前是 ,
这里就不考虑 ,所以 将保存上一次的状态,等价于上述的式子。
如果,之前是
现在是
两者都是在考虑个物品时容量为的最大价值,和上一状态要把这个物品放进去这两个状态之间
得到的最大价值。
既然都是等价的,理论上我们应该可以直接套用这个新的板子。
但是,
其实依然存在一些问题,等价但不完全等价,关键点在于循环顺序。
试着考虑这样的一个问题,我们考虑 状态和 状态:
状态的所面临的问题:
状态所面临的问题:
当 时我们可以看到:
对于同一个物品,在循环到和时都要考虑放与不放的问题,
所以我们可能在$ f[j]f[2j]$时我们又放了一次,
这就违背了题目中每个物品只有一件的题意。
问题出在哪里?
理论上难道不是等价的吗?
其实我们可以发现
这里的如果已经被更新过,那么它保存的就是这个状态,而不是上一个状态
真正的优化:
所以我们重新考虑循环的顺序,我们采用倒序循环,也就是
这样我们就可以保证中比较的状态都是上一个状态。
1|0完全背包
定义:
有种物品和一个容量为的背包,每种物品都有无限件可用。第 种物品的体积是 ,价值是 。
求解将哪些物品装入背包可使这些物品的体积总和不超过背包容量,且价值总和最大。
(与01背包的区别就是,物品可以无限使用。)
如果仍然按照解01背包时的思路:令 表示前 种物品恰放入一个容量为 的背包的最大权值。
仍然可以按照每种物品不同的策略写出状态转移方程:
$ f[j]=max({f[j],f[j-kc]+kw})(0 \leq k*c \leq v)$
(k是所取物品的个数。)
说到多次使用,前一篇文章中提到过01背包的错误写法:顺序循环,
错误的原因便是在背包中可能多次的加入了同一件物品。
而这正是完全背包的写法:
__EOF__

本文链接:https://www.cnblogs.com/cyl-oi-miracle/p/16468091.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」