背包九讲
参考:AcWing题库
参考书目:背包九讲
1、01背包问题
- 题目描述:有 N 件物品和一个容量是 V的背包。每件物品只能使用一次。第 i件物品的体积是 vi,价值是 wi。求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
-
思路:动态规划,对于每一件物品遍历背包容量,当背包可容纳值大于等于当前物品,与之前已放进去的物品所得价值进行对比,考虑把是否需要置换。
- 状态转移方程:定义dp[i][j]:前i个物品,背包容量j下的最优解
-(1)当前背包容量不够,为前(i-1)个物品最优解:j<w[i]时,有dp[i][j]=dp[i-1][j]
-(2)当前背包容量够,判断选还是不选第i个物品:j>=w[i]时,选该物品->dp[i][j]=dp[i-1][j-w[i]]+v[i];不选该物品->dp[i][j]=dp[i-1][j]
- 状态转移方程:定义dp[i][j]:前i个物品,背包容量j下的最优解
## 伪代码:
# for i=1..N
# for v=V..0
# f[v]=max{f[v],f[v-c[i]]+w[i]};
- (color{red}{代码实现-github}):0-1背包
2、完全背包问题
-
题目描述:有 N 种物品和一个容量是 V的背包,每种物品都有无限件可用。第 i种物品的体积是 vi,价值是 wi。求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。
-
思路:
-
思路1:最简单的想法,就是将完全背包转化为0-1背包问题,可以将第 i 种物品转化为W/w[i]件费用及价值均不变的物品,然后求解0-1背包问题。
-
思路2:更高效的转化方法是第 i 种物品拆成费用为w[i]2k,价值为v[i]*2k的若干件物品,其中k满足w[i]2^k<=W。因为不管最优策略 选几件第 i 种物品,总可以表示成若干个 2^k 件物品的和(二进制思想)
-
思路3(完全背包优化):若两件物品i、j满足c[i]<=c[j]且w[i]>=w[j],则将物品j去掉,不用考虑。c表物品重量,w表示对应物品价值。即将重量大且价值低的物品去掉。
-
思路4(复杂度为O(VN)): 0-1背包问题中要按照 w=W..0 的逆序来循环,而完全背包必须按照从小到大的顺序。这是因为 要保证第 i 次循环中的状态 f[i][w]是由状态 f[i-1][w-w[i]]递推而来。换句话 说,这正是为了保证每件物品只选一次,保证在考虑“选入第 i 件物品”这件策 略时,依据的是一个绝无已经选入第 i 件物品的子结果 f[i-1][w-w[i]]。而现 在完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第 i 种物 品”这种策略时,却正需要一个可能已选入第 i 种物品的子结果 f[i][w-w[i]], 所以就可以并且必须采用 w=0..W 的顺序循环。
-
## 伪代码:
# for i=1...N
# for w=0...W
# f[w] = max(f[w], f[w-cost]+weight)
- (color{red}{代码实现-github}):完全背包