graph LR
BP(背包) ---> 01背包
BP ---> 完全背包
BP ---> 多重背包
BP ---> 混合背包
BP ---> ...
约定
第 $i$ 件物品具有价值 v[i]
和重量 w[i]
背包容量为 W
01 背包
每种物品只能被放入背包 1 次
朴素实现
设计状态 f[i][j]
i
$\Rightarrow$ 只考虑第 $1$ ~ $i$ 件物品的子问题j
$\Rightarrow$ 剩余容量f
$\Rightarrow$ 该子问题的答案 aka 最大价值
状态转移有两个分支
- 不选当前物品 $\Rightarrow$ 容量不变,价值不变
- 选择当前物品 $\Rightarrow$ 容量减少
w[i]
,价值增加v[i]
|
|
滚动优化
因为 f[i][j]
的 [i]
维度只有 [i - 1]
能影响 [i]
所以可以不断让 f[i]
覆盖在原来 f[i - 1]
的内存上 aka 滚动数组
状态转移方程如下
|
|
板子·01背包·滚动优化实现
|
|
时间复杂度 $O(W)$ 空间复杂度 $O(W)$
错误实现
|
|
实际上这是 完全背包 的解决方法
因为当 j >= w[i]
时,f[i][j]
会被 f[i][j - w[i]]
影响
相当于物品 i
可以被放入无限次
完全背包
每种物品能被放入背包 $\infty$ 次
板子·完全背包实现
|
|
时间复杂度 $O(W)$ 空间复杂度 $O(W)$
多重背包
每种物品能被放入背包 $\leq$ cnt[i]
次
板子·多重背包·朴素实现
|
|
时间复杂度 $O\left( W\sum k_{{i}} \right)$
多重背包错误实现
先枚举剩余重量,后枚举个数 $\implies$ ✅ 先枚举个数,再枚举剩余重量 $\implies$ ❌
二进制分组优化
枚举 cnt[i]
时,复杂度是 $O(cnt[i])$
而如果把 cnt[i]
分拆成二进制数
并根据数位拆成不同的物品
再对这些物品进行 01 枚举
时间复杂度是 $O(\log_{2}cnt[i])$
总时间复杂度变为 $O\left( W\sum \log_{2}cnt[i] \right)$
板子·多重背包·二进制分组实现
预处理
|
|
核心状态转移和 01 背包 一致
混合背包
每种物品能被放入背包 either
- 1 次
cnt[i]
次- $\infty$ 次
实现思路是枚举每个物品时,根据 物品的可放入次数 套用 相应的背包状态转移方程
|
|