十分感谢这位大大的讲解!
http://blog.csdn.net/liuqiyao_01/article/details/8521776
接下来为个人对01背包问题的理解:
每种物品数量均为1,每个物品都包含体积weight和价值value,而有一个Weight大小的背包,怎么装才能让这个背包里的总价值Value最大
首先,我们可以有下面这段代码:
dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
i为当前选取第i个物品,j为体积。
那么dp[i][j]的含义为,不选取这件物品(dp[i-1][j])和选取这件物品(dp[i-1][j-weight[i]]+value[i])的最大值。
后面选取这件物品可能有些难理解,我们解析一下。
这个j为什么是个变量?
因为当你选取了一个物品时,背包的体积就会改变为Weight-weight[i],所以从0(背包为满)到Weight(背包为空)这些都是可能发生的情况。
而这个dp[i-1][j-weight[i]]是什么含义?
当你选取了第i个物品,你需要将这个物品的weight[i]从j中减去,j-weight[i]就是当前剩余的体积,dp[i-1][j-weight[i]]就是选取第i个物品之前的(j-weight[i])的最大价值。
这两个难点搞定了之后,我们就有了下面的代码:
for(i=1;i<=n;i++)
for(j=0;j<=Weight;j++)
if(j>=weight[i])
dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
else
dp[i][j]=dp[i-1][j];
当选取第n个物品,背包大小为Weight的情况下,总价值的最大值就是dp[n][Weight]了。
注意这里采用的是二维数组,但我们可以用一维数组来节省空间。
for(i=1;i<=n;i++)
for(j=Weight;j>=weight[i];j--)
dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
注意到j的循环从正序变为倒序,原因是当j从大到小时,较小的j仍保存的是上一次循环的值,使用时相当于dp[i-1][j-weight[i]],若改为顺序的话,较小的j被更新为dp[i][j-weight[i]],与原来的顺序不符。