背包问题学习笔记Part1
背包问题
前言:背包问题的学习笔记和模板例题整理。
01背包
有件物品和一个容量为的背包。第件物品的费用是,价值是。求解将哪些物品装入背包可使价值总和最大。
分析:
- 每种物品都只有一件。
- 都只有放或是不放两种选择。
- 用表示只放入前个物品时在所用体积为时所能得到的最大价值。
- 由此可以得出状态转移方程式:
解释:
- 这是一个背包问题的原始状态转移方程式,有很多背包问题的变体都是从此推出而得
- 将前个物品放入背包这一过程只会与前个物品有关,也就是相当于只考虑第件物品是否放入的问题
- 如果不放入第件物品,那么问题转化为前件物品放入容量为的背包中,表示出来就是此时:
- 如果放入第件物品,那么问题转化为前件物品放入容量为的背包中,表示出来就是此时:
- 因为要取其中的最优策略,所以要取两种情况中的较大值
空间复杂度优化:
- 01背包的空间复杂度其实可以优化到级别
- 上面讲的思路如果要实现,首先要有一层的循环,控制每一次循环得出某个时的所有的值
- 是否能只用一个一维数组就保证在第次循环推的值时得到的就是之前的和的值呢?
- 其实在循环时用的顺序推出,这样就能保证得到的就是和中的较大值
核心部分代码:
for(int i=1;i<=n;i++)
for(int j=m;j>=1;j--)
f[j]=max(f[j-c[i]]+w[i],f[j]);
一些细节:
- 其实可以对上面的代码进行一个常数优化,因为如果循环中的比当前的要小,便没有继续推的必要,可以把
for(int j=m;j>=1;j--)
改为for(int j=m;j>=c[i];j--)
- 如果要求的是恰好装满背包情况下的最大价值,那么除了赋值为,除此之外的都要赋为极小值
- 如果要求的是不必装满背包情况下的最大价值(比如下面那道模板题),那么整个都赋值为
- 分成这两种情况的原因是:初始化数组时应该给其赋值在没有任何物品放入时的合法状态
- 如果要求恰好装满,那么没有物品情况下的唯一合法情况就是容量为的情况被“一无所有”装满时的价值,其他容量的背包均无合法的解,处于未定义状态,所以赋值为
- 如果不要求恰好装满,那么此时每个容量下的背包都有合法情况即不装任何物品,所以都赋值为
- 关于初始化的问题可以推广到其他种类的背包问题
模板题:
完全背包
有种物品和一个容量为的背包,每种物品都有无限件可用。第种物品的费用是,价值是。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
分析:
- 这个问题和01背包问题唯一的差别是这个问题里的物品可以取无数件
- 所以取物品的策略从取和不取两种决策变成取件
- 此时如果按照01背包的思想,令为前个物品放入体积为的背包中的最大价值,依然可以推出这种思路下的状态转移方程式:
- 这样做和01背包一样,有种情况,但是每种状况的讨论时间复杂度不在是常数。求出状态所需的时间复杂度是,总时间复杂度变为
优化:
- 完全背包问题有一个很简单有效的优化,是这样的:若两件物品、满足,则将物品去掉,不用考虑。这个优化的正确性显然:任何情况下都可将价值小费用高得换成物美价廉的,得到至少不会更差的方案。对于随机生成的数据,这个方法往往会大大减少物品的件数,从而加快速度。然而这个并不能改善最坏情况的复杂度,因为有可能特别设计的数据可以一件物品也去不掉。
- 这个优化可以简单的地实现,一般都可以承受。另外,针对背包问题而言,比较不错的一种方法是:首先将费用大于的物品去掉,然后使用类似计数排序的做法,计算出费用相同的物品中价值最高的是哪个,可以地完成这个优化。
转化:
- 考虑把完全背包问题转化为01背包问题来解。最简单的想法是,考虑到第i种物品最多选件,于是可以把第种物品转化为件费用及价值均不变的物品,然后求解这个01背包问题。这样完全没有改进基本思路的时间复杂度,但这毕竟给了我们将完全背包问题转化为01背包问题的思路:将一种物品拆成多件物品。
- 更高效的转化方法是:把第种物品拆成费用为、价值为的若干件物品,其中满足。这是二进制的思想,因为不管最优策略选几件第种物品,总可以表示成若干个件物品的和。这样把每种物品拆成件物品,是一个很大的改进。
的算法:
先放上代码:
for(int i=1;i<=n;i++)
for(int j=c[i];j<=m;j++)
f[j]=max(f[j],f[j-c[i]]+w[i]);
可以看出,上面的代码用的是一维数组,与01背包相比,只有第二重循环的循环次序有所不同。
为什么这样改就行?
- 01背包按照的顺序循环,是为了保证当前状态是由推得,即保证每件物品只选择一次
- 而完全背包的特点就是物品有无数件,所以在决定状态时,要考虑到状态
- 或者将基本思路中的方程式带入原方程,可以得到:
模板题:
多重背包
有 种物品和一个容量为 的背包。第 种物品最多有 件可用,每件费用是 ,价值是 。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
解法
其实多重背包与完全背包很相似,基本的状态转移方程也只是与之略有不同。
对于第 件物品,有 种策略:取 件。
还是令 为考虑前 个物品恰好放入 的空间时的最大价值。
此时的状态转移方程就是:
时间复杂度是:
多重背包也能二进制优化。
的解法
单调队列优化DP,本人不会,咕着,以后再补
甚至没有完全的模板题,不过多重背包应该还算好理解,毕竟有前面的铺垫了。
后记
背包问题学习笔记Part1就只写前三种最为经典的背包问题吧。
后面几种不是特别经典的留到后面。
在此之前要写另一篇博客,记录前三种背包问题的几道不是很难的变式题目,毕竟只会个模板完全不够。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix