动态规划中的背包问题总结

背包问题是动态规划中的一种经典题型, 背包问题的变体繁多且复杂,这里总结一下背包问题中的0-1背包、完全背包以及多重背包三类问题。

0-1背包问题

描述:有n件物品,每件物品的重量为w[ i ],价值为v[ i ],现在有容量为m的背包,问如何选择物品使得装入背包的物品价值总量最大。

对于这种问题,我们首先想到的就是遍历所有的情况,然后找到其中价值总量最大的,但是这个方法的时间复杂度为O(2n),复杂度太高了,因此需要用动态规划来求解该类问题,则可以使得时间复杂度降为O(nm)。

首先设置一个二维数组dp[][],其中dp[ i ][ j ]代表前 i 件物品装入容量为 j 的背包中价值总量最大值,则dp[ n ][ m ]即为所求问题的解。

对于第 i 件物品,我们有两种处理方法,即放或者不放:

  1. 若不放进去,则问题就转换为将前 i - 1个物品放入容量为 j 的背包中的问题,即dp[ i ][ j ] = dp[ i - 1 ][ j ]
  2. 若放进去,则放进去之前背包的容量不能超过 j - w[ i ],要保证能够放进第 i 件物品,即dp[ i ][ j ] = dp[ i ][ j - w[ i ] ] + v [ i ]。

所以由上面的分析可知,状态转移方程即为:

dp[ i ][ j ] = max(dp[ i - 1 ][ j ], dp[ i - 1 ][ j - w[ i ] ] + v [ i ])

对于边界条件,当容量为0或者物品数量为0时,最大价值量为0,即dp[ i ][ j ] = 0( i == 0 || j == 0)

上述二维数组dp的行代表的是更新的次数,因此我们其实可以将其转换为一维数组,优化后的状态转移方程为:

dp[ j ] = max(dp[ j ], dp[ j - w[ i ] ] + v [ i ])

但是由于涉及到两种更新的状态,即等式右边的dp都是上一次更新的结果,而左边则是这次更新的结果,因此我们需要采用逆序遍历所有的 j 的方法,这样就能保证在更新dp[ j ]的时候,dp[ j - w[ i ] ]没有被更新。

实例

参考如下几篇博客:
【牛客网】KY66 点菜问题
【牛客网】KY75 采药
【牛客网】KY14 最小邮票数

完全背包问题

完全背包问题与0-1背包问题的区别就在于,前者每件物品的数量是无限个,而后者只有一个。

同样的,首先设置一个二维数组dp[][],其中dp[ i ][ j ]代表前 i 件物品装入容量为 j 的背包中价值总量最大值,则dp[ n ][ m ]即为所求问题的解。

对于第 i 件物品,我们有两种处理方法,即放或者不放:

  1. 若不放进去,则问题就转换为将前 i - 1个物品放入容量为 j 的背包中的问题,即dp[ i ][ j ] = dp[ i - 1 ][ j ]
  2. 若放进去,则放进去之前背包的容量不能超过 j - w[ i ],要保证能够放进第 i 件物品,但是由于第 i 件物品仍然可以选择,因此不是转移到dp[ i - 1 ][ j - w[ i ] ],而是转移到dp[ i ][ j - w[ i ] ],即dp[ i ][ j ] = dp[ i ][ j - w[ i ] ] + v [ i ]。

所以由上面的分析可知,状态转移方程即为:

dp[ i ][ j ] = max(dp[ i - 1 ][ j ], dp[ i ][ j - w[ i ] ] + v [ i ])

对于边界条件,当容量为0或者物品数量为0时,最大价值量为0,即dp[ i ][ j ] = 0( i == 0 || j == 0)

可以发现,完全背包问题与0-1背包问题的状态转移方程的区别就在于前者是dp[ i ][ j - w[ i ] ],而后者则是dp[ i - 1 ][ j - w[ i ] ]

优化为一维数组的转移方程为:

dp[ j ] = max(dp[ j ], dp[ j - w[ i ] ] + v [ i ])

可以发现与0-1背包问题的是一样的,唯一不同的就是遍历的顺序不同,即0-1背包问题是逆序遍历 j ,保证第 j - w[ i ]是上一次更新的结果,而完全背包问题则是顺序遍历 j ,保证第 j - w[ i ]是这一次更新的结果

实例

参考如下博客:
【POJ】1384 Piggy-Bank

多重背包问题

多重背包问题是0-1背包问题与完全背包问题的一个折中,即每一件物品的数量不是只有一个,也不是无限个,而是k个,问题描述为:有n件物品,每件物品的重量为w[ i ],价值为v[ i ],数量为k[ i ],现在有容量为m的背包,问如何选择物品使得装入背包的物品价值总量最大。

对于这类问题,我们可以将其处理成0-1背包问题,即根据k将其分解,成多件物品,之后就转换为0-1背包问题了。我们可以将其分解为20,21,22,…,2c,k - 2c + 1,其中c为使得k - 2c + 1 >= 0的最大整数,之后的步骤就和0-1背包问题的求解步骤一样。

实例

参考如下博客:
【AcWing】4. 多重背包问题 I

你可能感兴趣的:(刷题笔记,动态规划,动态规划,算法)