小辣鸡写一些自己对0-1背包问题的详解,以防自己以后忘了。。。。
有4个物品,编号为1,2,3,4,重量w :10,2,4,5。价值v:5,3,7,8。容量W=20,总价值为V
dp[i][j]表示从编号为i包括i以前的前i个物品中选择,使得在容量为j的情况下,总价值V最大。
即dp[1][j<10]都为0,而dp[2][2]却不为0,因为是从1和2两个物品中选择,可以选择物品2,此时dp[2][2]=3。
分析可知dp[0][0<=j<=V] = 0。
对于第i个物品来说,
若把第i个物品放入背包,则dp[i][j] = dp[i-1][j-i.w]+i.v (i.w表示第i个物品的重量,i.v表示第i个物品的价值)
若第i个物品不放入背包,则dp[i][j] = dp[i-1][j]。
所以转移方程为dp[i][j] = max(dp[i-1][j], dp[i-1][j-i.w]+i.v)
核心代码是:
for(int i = 1; i <= n; i++)
{
//随着物品的增加,体积从s开始逐渐减少,
for(int j = s; j >= list[i].w; j--)
dp[i][j] = max(dp[i-1][j], dp[i-1][j-list[i].w]+list[i].v);
//当容量小于物品的价值的时候, 对应的dp[i][j]保持不变
for(int j = list[i].w-1; j >= 0; j--)
dp[i][j] = dp[i-1][j];
}
将数值代入分析:
i = 1
dp[1][20] = max(dp[0][20], dp[0][20 - 10] + 5) = 5
dp[1][19] = max(dp[0][19], dp[0][19 - 10] + 5) = 5
dp[1][18] = max(dp[0][18], dp[0][18 - 10] + 5) = 5
........
dp[1][10] = max(dp[0][10], dp[0][10 - 10] + 5) = 5
dp[1][0-9] = 0
i = 2
dp[2][20] = max(dp[1][20], dp[1][20 - 2] + 3) = 8
dp[2][19] = max(dp[1][19], dp[1][19 - 2] + 3) = 8
dp[2][18] = max(dp[1][18], dp[1][18 - 2] + 3) = 8
........
dp[2][11] = max(dp[1][11], dp[1][11 - 2] + 3) = max(5 , 0 + 3) = 5
.....
dp[2][2] = max(dp[1][2], dp[1][2 - 2] + 3)
dp[2][0-1] = dp[1][0-1]
i = 3
dp[3][20] = max(dp[2][20], dp[2][20 - 4] + 7) = 15
dp[3][19] = max(dp[2][19], dp[2][19 - 4] + 7)
dp[3][18] = max(dp[2][18], dp[2][18 - 4] + 7)
......
dp[3][15] = max(dp[2][15], dp[2][15 - 4] + 7) = 12 (表示前3个物品中选择了1和3,没有选择2)
.....
dp[3][4] = max(dp[2][4], dp[2][4 - 4] + 7)
dp[3][0-3] = dp[2][0-3]
i = 4
dp[4][20] = max(dp[3][20], dp[3][20 - 5] + 8) = 20
dp[4][19] = max(dp[3][19], dp[3][19 - 5] + 8)
.....
dp[4][5] = max(dp[3][5], dp[3][5 - 5] + 8)
dp[4][0-4] = dp[3][0-4]
最终dp[4][20] 就是最优的解。