背包问题
背包问题
01背包
有 \(n\) 个物品,第 \(i\) 个物品价值为 \(w_i\),体积为 \(c_i\),求将哪些物品装入容量为 \(m\) 的背包可使价值最高。
这是最基础的背包问题,特点是:每种物品只有一件,可以选择放或不放。
朴素的考虑如何划分子问题:
那么不妨考虑按照物品来划分阶段,先考虑前 \(i\) 个物品的最优解。
显然,状态转移过程中,只知道当前考虑到第几个物品,是无法判断转移是否合法的,我们还关心剩余的容量是否足以放下这些物品。
因此定义状态 \(f(i, v)\) 表示前 \(i\) 件物品恰好放入一个容量为 \(v\) 的背包可以获得的最大价值。
那么考虑到第 \(i\) 个物品时,有哪些可能转移呢?这是一个简单的问题:
- 选这件物品。
- 不选这种物品。
因此状态转移方程为:
其中 \(c_i\) 为代价,\(w_i\) 为价值。
时间复杂度为 \(O(nm)\)。
那么再确定初始状态,这个问题就解决了。
因为我们状态的定义为 \(f(i, v)\) 表示前 \(i\) 件物品恰好放入一个容量为 \(v\) 的背包可以获得的最大价值。所以初始状态的定义应该是:
- \(f(0, 0) = 0\)
- \(f(i, j) = -\infty(i \ne 0\ or\ j \ne 0)\)
实际上如果不要求体积恰好为 \(v\),而是不超过 \(v\) 即可,那么初始状态可 以进行细微改动,\(f(0, *) = 0\),即认为最初剩余容量可以为任意数。
\(\color{#A4CAE8}\large\texttt{空间优化}\)
观察状态转移方程
\(f(i, v) = max(f(i - 1, v), f(i - 1, v - c_i) + w_i)\)
发现 \(f(i, *)\) 仅从 \(f(i - 1, *)\) 转移,所以不保留更早的 \(f\) 优化空间。
用 \(f(i \& 1, *)\) 来表示 \(f(i, *)\),空间复杂度 \(O(m)\)。
实际上数组甚至可以压缩到一维,只需要注意状态转移时的循环顺序。
\(f(v) = \max\{f(v), f(v - c_i) + w_i\}\)
每次考虑第 \(i\) 个物品时,\(v\) 按照从小到大的顺序枚举。
因为 \(v\) 只会从小于等于 \(v\) 的状态转移而来。
这样的枚举顺序保证 \(f(v - c_i)\) 在被转移时时仍处于未更新状态,即 \(f(i - 1, *)\) 的状态。
for(int i = 1; i <= n; i ++)
for(int v = m; v >= c[i], v --)
f[v] = max(f[v], f[v - c[i]] + w[i]);
\(\color{#078DE4}\large\texttt{多重背包}\)
有 \(n\) 种物品和一个容量为 \(m\) 的背包。第 \(i\) 种物品最多有 \(a_i\) 件可用,每件的体是 \(c_i\),价值是 \(w_i\)。求将哪些物品装入背包可使这些物品的体积总和不超过背包容量,且价值总和最大。

浙公网安备 33010602011771号