算法-背包DP

背包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$ 件物品所选次数后得到的最优结果。换言之,我们通过局部最优子结构的性质重复使用了之前的枚举过程,优化了枚举的复杂度。