前提摘要见上一篇
01背包问题时间和空间复杂度都是O(nV), 空间复杂度可以继续优化为O(V) 算法笔记P444
滚动数组代码
1 dp[N];//这里只用一维的 2 for(int i=1; i<=n; i++)//对每个数判断,可反 3 { 4 for(int j=m; j>=weight[i]; j--)/ 5 dp[j]=max(dp[j],dp[j-weight[i]]+value[i]); 6 }
这里用到还是熟悉的数据熟悉的内容:
体积 | 价值 |
0 | 0 |
4 | 8 |
6 | 10 |
2 | 6 |
2 | 3 |
5 | 7 |
1 | 2 |
然后开始循环,先说下代码里面的n是物品,m是背包容量:,真实的值是n=6,m=12
1)
最初i=1,j=12表示只有1号物品也就是(4-8),背包容量为12时候。这时候dp[12]=max(dp[12],dp[12-4(1号物品体积)]+8(1号物品价值)])=8;
这样一直到m[1][4]都是8,。当包容量小于此时1号物品容量时候跳出循环。
这时候dp数组
dp[]下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
值 | 0 | 0 | 0 | 0 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 |
2)
这是第二次n循环,这时候i=2,包含了一号物品(4-8)和二号物品(6-10) ;此时包可以装下
dp[12]=max(dp[12],dp[12-6]+10)=dp[12-6]为8所以这dp[12]=18.同理dp[10]dp[11]都是18。
dp[9]-dp[6]时候 比如max(dp[9],dp[9-6]+10)=dp[3]为0所以最终为10。没问题的话最终【0,0,0,8,8,8,10,10,10,18,18】
这时候dp数组
dp[]下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
值 | 0 | 0 | 0 | 0 | 8 | 8 | 8 | 8 | 8 | 10 | 18 | 18 | 18 |
3)
i=3, 包含了一号物品(4-8)和二号物品(6-10) 和三号物品(2-6),
dp[12]=max(dp[12],dp[12-2]+6) = dp[12-2]+6 =24
dp[11]=max(dp[11],dp[11-2]+6) = dp[11]=18
dp[10]=max(dp[10],dp[10-2]+6) = dp[10] =18
dp[9]=max(dp[9],dp[9-2]+6) = dp[7] +6 =14
dp[8] dp[7] dp[6] =14
dp[5] dp[4] = 8
dp[3] = dp[1]+6 = 6
dp[2]=6
dp[]下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
值 | 0 | 0 | 6 | 6 | 8 | 8 | 14 | 14 | 14 | 14 | 18 | 18 | 24 |
到这里气候就差不多了,下面都是类似的。
看起来没什么问题了。
不用滚动数组的话代码这样
这就是上一次的数值。滚动数组是把它保留了然后从后往前更新,直到背包容量小于物品容量的话更新就不用了,直接拿上一次就好了。