背包DP
引入
在具体讲何为背包dp前,先来看如下的例题:
Charm Bracelet
在上述例题中,由于每个物体只有两种可能的状态(取与不取),对应二进制中的0和1,这类问题便被称作0-1背包问题。
0-1背包
解释
例题中已知条件有第i个物品的重量 ,价值 以及背包的总重量 。
设DP状态 为在只能放前 个物品的情况下,容量为 的背包所能达到的最大总价值。
考虑转移。假设当前已经处理好了前 个物品的情况下,那么对于第 个物品当其不放入背包时,背包的剩余容量不变,背包中物品的总价值也不变,故这种情况的最大价值为 $f{i-1,j}w_iv_if{i-1,j-w_{i}}+ v_i$
由此可以得出状态转移方程:
这里如果直接采用二维数组对状态进行记录,会出现MLE。可以考虑改用滚动数组的形式来优化。由于对 $fif{i-1}f_ii$ 的最大价值,得出以下方程:
务必牢记并理解这个转移方程,因为大部分背包问题的转移方程都是在此基础上推导出来的。
实现
1 2 3 4 5
| for(int i=1; i<=n; i++){ for(int l= W; l>=w[i];l--){ f[l] = max(f[l],f[l-w[i]]+ v[i]); } }
|
完全背包
解释
完全背包模型与 背包类似,与 背包的区别仅在于一个物品可以选取无限次,而非仅能选择一次。
我们可以借鉴 背包的思路,进行状态定义:设 为只能选前 个物品时,容量为 的背包可以达到的最大价值。
需要注意的是,虽然定义与 背包类似,但是其状态转移方程和 并不相同。
过程
可以考虑一个朴素的做法:对于第 件物品,枚举其选了多少个来转移。这样做的时间复杂度时 的。
状态转移方程如下:
考虑做一个简单的优化。可以发现,对于 $f{i,j}f{j,j-w_i}$ 转移就可以了。因此状态转移方程为:
理由时当我们这样转移时,$f{i,j-w_i}f{i,j}-2\times wif{i,j-w_i}i$ 件物品所选次数后得到的最优结果。换言之,我们通过局部最优子结构的性质重复使用了之前的枚举过程,优化了枚举的复杂度。