简介
背包问题是一类动态规划问题的统称,分有多种子类型。
01背包
给定(n)个物品,每个物品都有自己的价值(v_i)和重量(w_i)。现有一个容量为(W)的背包,求最大价值。
很容易想到每种物品只有选或者不选,那么依次枚举即可。
考虑到还需要判断能否装下这些物品,所以还需要在转移的时候维护剩余容量。
因此设子状态(f[i][j])为当前在第(i)个物品处,包括(i)在内已经选了重量为(j)的物品的最大价值。
状态转移方程为(f[i][j]=max(f[i-1][j-v_i]+w[i],f[i-1][j]))
此时的空间复杂度为(O(NM)),可以通过滚动数组优化到(O(M))。
事实上,还可以进行进一步优化:
由于每一层(i)之间是互相独立的(也就是说(f[i][j])不会被(f[i][k])更新),所以我们可以优化掉第一维,但是此时需要修改第二维的枚举顺序。
根据状态转移方程可知,第二维大的状态是由第二维小的状态转移来的,由于我们优化掉了第一维,所以必须先遍历第二维大的状态,否则将会出现覆盖的情况。
所以第一维遍历仍然顺序,第二维遍历须改为逆序。
完全背包
条件和01背包一致,但是每种物品都有无限个。
子状态与上一题一致,但是转移过程有不同。
我们将上一题中第二维的遍历顺序改为顺序即可解决完全背包问题。
改为顺序后,即会出现同层之间互相转移的情况,也就是实现了每个物品可以无限选取的题设。
多重背包
条件与01背包一致,但是每种物品都有(c_i)个。
朴素的思路是将每种物品拆开,转换为01背包进行求解,时间复杂度为(O(msum c_i))。
更为优秀的思路是将每种物品个数量按照二进制拆开。
对于物品(i),把它拆成重量为(2^0*v_i,2^1*v_i,...,2^p*v[i],r_i*v_i)的物品,显然([1*v_i,c_i*v_i])中的所有重量都能被组合出来。
这样的时间复杂度为(O(mlogc_i))。
分组背包
有(n)组,每组都有(m)个物品,每组最多选一个,求最大价值。
子状态(f[i][j])表示选到了第(i)组,总重量为(j)的最大价值。
(f[i][j]=max(f[i-1][j],max(f[i-1][j-v_{ik}]+w_{ik})))
可以像01背包一样优化掉第一维。