动态规划 (三) 背包问题
来源:互联网 发布:阴阳师6星土豪酒吞数据 编辑:程序博客网 时间:2024/06/05 17:19
问题描述
有n个物品,且每个物品都只有一个。物品i的体积为v[ i ],重量为w[ i ]。背包的体积为C,求怎样装载能使得背包里装的物品最重?
思路分析
之所以叫0-1背包问题,是因为所有的物品都只有一个,在选择物品装载到背包里的时候,只有两种选择:不装载或装载,对应计算机里的0(FALSE)和1(TRUE)的概念。我们用 dp[ i ][ j ] 表示“把前 i 个物品装到体积为 j 的背包中的最大总重量”。得状态转移方程:
dp[i][j] = max(dp[i-1][j], dp[i-1][j - v[i]] + w[i]);其中,dp[ i - 1 ][ j ] 表示不把物品 i 装载进背包,所以背包的重量是前面 i-1 个的重量;后一项 dp[ i - 1][ j - v[ i ] ] + w[ i ] 表示若把第 i 个物品装载进背包,则必须由最优子问题得到,所以没装载 i 之前重量一定也是最大的。
我们发现循环的时候,这个转移方程是一个二维数组,且第 i 行取决于第 i -1行的值,因此初始化时,只要将第 0 行全部置为 0 即可,即 dp[ 0 ] [ j ] = 0;
代码示例
for(int j = 0; j <= C; ++ j) {dp[0][j] = 0;}for(int i = 1; i <= n; ++ i) {scanf("%d %d", &v, &w);for (int j = 0; j <= C; ++ j) {if(j >= v) {dp[i][j] = max(dp[i-1][j], dp[i-1][j - v] + w);} else {dp[i][j] = dp[i-1][j];}}}
dp[ i ][ j ] 表示“把前 i 个物品装到体积为 j 的背包中的最大总重量”。所以外循环 i 表示从前1个物品到前n个物品,内循环 j 表示体积从 0 到 最大的 C。由于数据是一样样计算的,所以可以不用提前把所有的数据都读好,也不用存起来。
滚动数组
更奇妙的是,我们可以把数组dp编程一维的,这里非常的精妙和巧合,但是要注意这只是程序代码的优化,并不是说 0 - 1 背包问题就是一维背包问题。
memset(dp, 0, sizeof(dp)); for (int i = 1; i <= n; ++ i) {scanf("%d%d", &v, &w);for(int j = C; j >= v; j --) {dp[j] = max(dp[j], dp[j-v] + w);}}
考虑为采用滚动数组的情况,f[ i ][ j ]的值要么是f[ i - 1][ j ],要么是f[ i - 1][ j - v ] + w;由于j是从右往左计算的,所以现在f[j]里保存的是f[ i - 1 ] [ j ],而f[j - v]里保存的是f[ i - 1 ] [ j - v ]的值,所以正好可以。这样子的话,我们可以节省了不少空间的代价。
注意内循环 j 是到 v 即停止了的,这样子就不用判断 j 和 v 的关系了,因为 j >= v 始终成立。若是 j < v 的情况,f[ j ] 中本来就保存了 f[ i - 1][ j ]的信息,也不用更新。
若背包必须装满
此外,若题目要求,背包必须装满,则只需要改一下初始化的条件就行。
memset(dp, -0x3f3f, sizeof(dp));dp[0] = 0;for(int i = 1; i <= n; ++ i) {scanf("%d%d", &v, &w);for(int j = C; j >= v; -- j) {dp[j] = max(dp[j], dp[j-v] + w);}}
背包九讲里是这样子解释的:初始化的过程,实际就是说,当一件物品都没有时的解。所以若要求必须装满背包,只有一种解,就是dp[0],即让价值为0的物品,恰好装进容量为0的包里。其他的都是非法解,所以初始化为负∞才行。而没有要求一定要装满背包的情况下,则所有的解都可以是正确的解,所以可以初始化为0;
可重复背包问题
可重复背包是说,每种物品的个数是无限的,而不是0-1背包中,物品只有一个。相似的,有状态转移方程:
dp[i][v]=max{ dp[i-1][v-k*c[i]]+k*w[i] | 0<=k*c[i]<=v }就是说,这个物品可以选 0 次,1 次,2次... v / c[i] 次,知道装不下为止。
但是也有O(NV)复杂度的优化,而且代码很简单,就是上面的滚动数组实现0-1背包,内循环 j 倒过来就行了。原理不明,可能是我水平太低了,目前无法理解。
伪代码如下:
procedure CompletePack(cost,weight) for v=cost..V f[v]=max{f[v],f[v-c[i]]+w[i]}
参考资料
- 《算法竞赛入门经典》 & 《训练手册》 刘汝佳
- 背包九讲
- 刷题的博文
0 0
- 动态规划 (三) 背包问题
- 动态规划(三)背包问题
- 【动态规划(三)】经典背包问题
- 动态规划入门三---背包问题(1)
- 【动态规划】三种基本背包问题
- 背包问题(动态规划)
- 背包问题(动态规划)
- 背包问题(动态规划)
- 背包问题(动态规划)
- 动态规划 背包问题
- 【动态规划】背包问题
- 动态规划-背包问题
- 动态规划+背包问题
- 动态规划-背包问题
- 背包问题 -- 动态规划
- 《背包问题》 动态规划
- 动态规划-背包问题
- 动态规划 背包问题
- usb驱动框架(usb-skeleton)分析总结
- SanguoSHA - HDU 4068 暴力枚举
- Java 跳出多重循环
- JAVA 实现线性表之链表
- poj2363
- 动态规划 (三) 背包问题
- hello world
- 黑马程序员——java for循环学习总结
- 花生壳绑定IP解决动态IP问题
- 算法设计之蛮力法
- 算法笔记--八个常见排序算法总结
- 程序员生存定律-六个程序员的故事(3)
- C#调用Web Service简单实例
- java线程