背包细节补充
背包问题为什么要去枚举背包容量 j ?而且在状态转移中,为什么考虑选第 i 种物品时的转移方程是 dp[ j ] = max ( dp[ j ], dp[ j - v[ i ] ] + w[ i ]) ?
背包问题状态转移的思想就是 :
假设考虑前 i 个物品,此时枚举到背包容量 j
如果第 i 个物品的体积大于背包容量 j ,那么肯定不会考虑选第 i 个物品,那么此时 dp[ i ][ j ] = dp[ i - 1][ j ];
即直接继承考虑前 i - 1 个物品,背包容量为 j 时的最优解
反之,则需要考虑选第 i 个物品,那么此时就是要比较一下选第 i 个物品划算还是不选第 i 个物品划算
不选的情况就等于 dp[ i - 1][ j ],若是选第i个物品,则选入背包后,此时背包价值为w[ i ],背包容量剩余 j - k ,我们还要最大化利用剩下的 j - k 个空间
即再加上dp[ i - 1][ j - k ] (我要重新强调一下dp数组的含义是考虑前i个物品,背包容量为 j 能获取到的最大价值)
我想我说明白了状态转移的过程,接下来我要解释不同的初始化方式对于dp数组含义的影响
( 1 )如果你将dp数组初始化为全0,则此时dp数组的含义是考虑前 i 个物品,背包容量为 j 时能获取的最大价值,此时dp[ N ][ M ]即为答案
( 2 )如果将dp数组初始化为负无穷,而只有dp[ 0 ][ 0 ]为0,此时dp数组的含义就变成了考虑前 i 个物品,背包容量恰好为 j (也即没有空间浪费)时能获取的最大价值
此时dp[ N ][ M ]不一定是答案,需要遍历数组来寻找最大价值
证明过程 : (使用滚动数组优化)
初始化情况为 ( 1 ),设背包容量恰好为 k 时(k < M)取到了最大值
那么可以证明,dp[ k ]一定是由dp[ 0 ]一步步转移过来,通俗的说,就是我恰好选了k体积的物品,使得原体积为 M 的背包取得了最大价值
那么dp[ M ]同样可以视为由dp[ M - k ]转移而来(这里可以证明,dp[ M - k ] 一定等于 0 ,因为若dp[ M - k ]不为0,则最大价值一定不是恰好选 k 体积物品得到的,因为还有剩下的 M - k 个空间可以利用)
具体一些,就是dp[ M - k ] 的状态再选择 k 体积物品得到了 dp[ M ] ,所以,dp[ M ] = dp[ k ] 同理可以证明 k 到 m 之间的数 x 也满足上面的结论(dp[ x ] = dp[ k ])
此时dp数组的含义是考虑前 i 个物品,背包容量为 j 时能获取的最大价值
如果初始化情况为 (2), 那么就和上面的情况有差别了,dp[ k ]可以由dp[ 0 ]转移过来,但是dp[ M ] 不再可能由 dp[ M - k ]转移过来,因为初始化的时候只是将dp[ 0 ]设置为0
此时dp数组的含义就是考虑前 i 个物品,背包容量恰好为 j 时能获取的最大价值
所以循环结束,dp数组会呈现一种有效答案和无效答案(负无穷)混合出现的情况,若不是恰好把M个空间都利用上了,dp[ M ] 就会是负无穷,所以dp[ M ]不再一定是答案
本质来说,其实不是初始化的方式直接导致了dp数组含义的不同,而是相同的状态转移过程是否可以发生在多个最初状态上,比如这个问题中,初始化为全0就使得k 到 m 之间的数 x 也可以由一些初始状态转移而来,而只将dp[ 0 ]初始化为0导致了只有dp[ k ] 可以由 dp[ 0 ] 一步步转移而来,dp数组含义就发生了变化

浙公网安备 33010602011771号