「算法笔记」背包问题解题思路
本文中,约定物品个数为 \(n\),背包的最大价值为 \(m\)。
多重背包问题的转化
- 可以通过把一个多重背包中的物品拆成多个 \(01\) 背包中的物品(每次大小翻倍,最后余下的单独拆出一个物品)。插入一个物品的复杂度为 \(O(m \times \log m)\)。比较好写,较常用。
- 可以使用单调队列来优化 \(\text{DP}\),插入一个物品的复杂度为 \(O(m)\)。比较难写,卡常时用。
完全背包的特殊性质
- 对于物品集合 \(A\) 和物品集合 \(B\),\(A \bigcup B\) 的完全背包就等于 \(A\) 的完全背包和 \(B\) 的完全背包合并的结果。
- 如果有多个大小相同的物品,肯定是取价值最大的物品最优。
任意背包的通用思路
- 合并两个背包的时间复杂度是 \(O(m^2)\),而加入一个物品的复杂度是 \(O(m)\) 左右。于是解决问题时,我们尽量避免合并两个背包。
- 如果只计算每种体积是否可以达到,可以用 \(\text{bitset}\) 进行常数优化。
- 如果计算方案数,背包可以删除物品,否则不行。
例题试炼
例题一:
\(q\) 个询问。每次问区间 \([l, r]\) 的完全背包。强制在线。
\(n, q \le 10^5, m \le 30\)。
线段树维护区间大小为 \(k (1 \le k \le m)\) 的最大价值,对于每个询问做完全背包即可。时间复杂度 \(O(n \times \log n \times m + q \times m^2)\)。
例题二:
询问对于 \(1 \le i \le n\),除了第 \(i\) 个物品以外的物品的 \(01\) 背包。
\(n, m \le 3000\)。
分治,递归到左半边时加入右半边的物品,递归到右半边时加入左半边的物品。时间复杂度 \(O(n \times \log n \times m)\)。
例题三:
一棵树,每个点都是物品。\(q\) 次询问,每次询问两点路径 \(01\) 背包。
\(n, q \le 10^5, m \le 30\)。
直接树上倍增需要合并背包,效率低下。考虑点分治,对于 \(\text{DFS}\) 只需加单个物品,处理询问时只需合并两个背包。时间复杂度 \(O(n \times \log n \times m + q \times m^2)\)。
“记录算法学习的点点滴滴”