动态规划(二)背包问题
背包是线性DP中重要且特殊的一类模型,可以分为0/1背包、完全背包、多重背包和分组背包四类。
0/1背包
问题模型
给定 $N$ 个物品,其中第 $i$ 个物品的体积为 $V_i$,价值为 $W_i$。有一个容积为 $M$ 的背包,要求选择一些物品放入背包,使得物品总体积不超过 $M$ 的前提下,物品的总价值和最大。
阶段:用已处理的物品数作为 DP 的阶段,以背包中已经放入的物品的总体积作为附加维度。
$ F[i, j]$ 表示从前 $i$ 个物品中选出了总体积为 $j$ 的物品放入背包,物品的最大价值和。则有状态转移方程:
$$
F[i][j] = max
\left\{
\begin{array}{**lr**}
F[i-1,j], & 不选第i个物品 \\
F[i-1, j-V_i] + W_i \;(if \;j\geq V_i )& 选第i个物品
\end{array}
\right.
$$
初始值:$F[0, 0] = 0$,其余为负无穷,目标:$ \max \limits_{0 \leq j \leq M}\{F[N][j]\}$。
求解代码
1 | memset(f, 0xcf, sizeof(f)); |
经过状态压缩之后
1 | memset(f, 0xcf, sizeof(f)); |
一般问题可能有两类,一类是问最大值,一类是问方案数目。决策转移时,分别使用最大值判断和相加即可。
完全背包
问题模型
给定 $N$ 个物品,其中第 $i$ 个物品的体积为 $V_i$,价值为 $W_i$ ,并且有无数个。有一个容积为 $M$ 的背包,要求选择一些物品放入背包,使得物品总体积不超过 $M$ 的前提下,物品的总价值和最大。
阶段:用已处理的物品数作为DP的阶段,以背包中已经放入的物品的总体积作为附加维度。
$ F[i, j]$ 表示从前 $i$ 种物品中选出了总体积为 $j$ 的物品放入背包,物品的最大价值和。则有状态转移方程:
$$
F[i][j] = max\left\{
\begin{array}{**lr**} F[i-1,j], & 不选第i种物品 \\
F[i, j-V_i] + W_i \;(if \;j\geq V_i )& 从第i种物品种选择一个
\end{array}
\right.
$$
初始值:$F[0, 0] = 0$,其余为负无穷,目标:$ \max \limits_{0 \leq j \leq M}\{F[N][j]\}$。
求解代码
直接放经过状态压缩之后的代码。
1 | memset(f, 0xcf, sizeof(f)); |
多重背包
问题模型
给定 $N$ 个物品,其中第 $i$ 个物品的体积为 $V_i$,价值为 $W_i$ ,并且有 $C_i$ 个。有一个容积为 $M$ 的背包,要求选择一些物品放入背包,使得物品总体积不超过 $M$ 的前提下,物品的总价值和最大。
直接拆分法:把第 $i$ 种物品看作独立的 $C_i$ 个物品,从未转化为0/1背包问题,但时间复杂度较高。
二进制拆分法:待补充。
单调队列法:待补充。
例题:Coins
给定 $N$ 种硬币,其中第i种硬币的面值为 $A_i$,共有 $C_i$ 个。从种选出若干硬币,把面值相加,若结果为 $S$,则称“面值 $S$ 能被拼成”。求 1~N 之间能被拼成的面值有多少个。
$1\leq N\leq 100, 1\leq M \leq 10^5, 1 \leq A_i \leq 10^5, 1 \leq C_i \leq 1000$。
以“已考虑过的物品种数”作为 DP 的阶段,在阶段 $i$ 时,$F[j]$ 表示前i种硬币是否能够拼成面值 $j$。“直接拆分法”的求解片段。
1 | bool f[100010]; |
上述代码复杂度过高,进行优化。
前i中硬币能够拼成面值 $j$,只有两种可能情况:
- 前 $i-1$ 种硬币已经可以拼成面值 $j$。
- 使用了第 $i$ 种硬币,在第 $i$ 阶段递归时,发现 $F[j-a[i]]$ 为 true ,从而 $F[j]$ 变为true。但是该种条件下应该满足,$F[j-a[i]]$ 为 true 时,使用的第 $i$ 种硬币应该小于 $C_i$。
假设 $used[j]$ 表示 $F[j]$ 在阶段 $i$ 时为 true 至少需要多少枚第 $i$ 种硬币。
1 | int used[100010]; |
分组背包
问题模型
给定 $N$ 个物品,其中第 $i$ 组有 $C_i$ 个物品。第 $i$ 组的第 $j$ 个组品的体积为 $V_{ij}$,价值为 $W_{ij}$ 。有一个容积为 $M$ 的背包,要求选择一些物品放入背包,使得每组至多选择一个物品并且物品总体积不超过 $M$ 的前提下,物品的总价值和最大。
$ F[i, j]$ 表示从前 $i$ 组物品中选出了总体积为 $j$ 的物品放入背包,物品的最大价值和。则有状态转移方程:
$$
F[i][j] = max
\left\{
\begin{array}{**lr**}
F[i-1,j], & 不选第i组物品 \\
\max \limits_{1\leq k\leq C_i} F[i-1, j-V_{ik}] + W_{ik} \;(if \;j\geq V_{ik} )& 选第i组的某物品k
\end{array}
\right.
$$
求解代码
经过空间压缩后的求解代码
1 | memset(f, 0xcf, sizeof(f)); |
Author: Hatton.Liu
Link: http://hattonl.github.io/2020/02/15/dynamic-programming-1/
License: 知识共享署名-非商业性使用 4.0 国际许可协议