背包问题
以集合的角度思考背包问题
当面对dp问题,首先考虑两个内容:(1)状态表示(2)状态计算
(1)状态表示
- 集合:f(i)(j) 表示一个集合,这个集合包含不同的选法。
- 条件:这个集合表示,选前 i 件物品,且总体积不大于 j 的选法。
- 属性:f(i)(j) 的值代表 max?还是min?还是某个数x的个数?等等...
(2)状态计算
状态计算就是将集合拆分,拆成多个子集合,每个子集合用不同的式子表达。
切分的依据是:“寻找最后一个不同点”
01背包
特点:每件物品只能使用一次。
用集合的角度看待01背包问题:
(1)状态表示:
假设物品共有N件、物品总体积为V。那么 f(i)(j) {0<i<=N,0<j<=V}
表示:
-
集合:从背包中选前 i 件物品,且物品总体积小于 j 的选法集合。
例如 f(4)(7) 表示选前4件且总体积不大于7的各种选法。 -
属性:所有选法对应价值中的最大值。
例如 f(4)(7) 的各种选法中,哪个价值最大。
(2)状态计算:
通过是否包含第 i 件,将集合 f(i)(j) 拆分成两部分。最终 f(i)(j) = max(集合1,集合2)
-
集合1:选的物品不包含第 i 件(或者说选前 i - 1 件),且体积不大于 j
表达式:f(i - 1)(j)
-
集合2:选的物品包含第 i 件,且体积不大于 j
难点:如何表示包含第i件? 曲线救国,假设现在已经装有第 i 件,然后把第 i 件拿出,此时背包最大价值为f(i - 1)(j - V(i) )
,然后再将第 i 件装回,则包含第 i 件的背包最大价值为f(i - 1)(j - V(i) ) + W(i)
最终得出:f(i)(j) = max( f(i - 1)(j), f(i - 1)(j - V(i) ) + W(i) )
优化为一维数组
为什么可以优化?
若将 f(i)(j) 看作二维数组,那么 i 只和 i - 1 有关,即下一行由上一行得出。而 j 也只和上一行的 j 和 j-V(i) 有关,即下一行的每一项,由上一行同位置左侧的值得出。