初学完01背包和完全背包后一点总结.
//1:01背包:
for(int i=1;i<=n;i++)
for(int j=m;j>=v[i];j--)
f[j]=max(f[j],f[j-v[i]]+w[i]);
//2:完全背包:
for(int i=1;i<=n;i++)
for(int j=v[i];j<=m;j++)
f[j]=max(f[j],f[j-v[i]]+w[i]);
两者粗看完全一样,实则有所区别:
内层循环中j循环的顺序分别为正序和倒序
解释原因前,我们先看两者优化前的代码:
//1.01背包:
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
f[i][j]=f[i-1][j];
if(v[i]<=j)f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
}
//2.完全背包:
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
f[i][j]=f[i-1][j];
if(v[i]<=j)f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);
}
可以看见,两者取max时的第二个数有所不同:
在01背包中是f[i-1][j-v[i]]+w[i];
在完全背包中是f[i][j-v[i]]+w[i];
而优化后我们仅用一维数组f[N](下标是体积)来存最大值,很关键的是j-v[i]<j,因此当我们正序遍历j时,我们遍历到f[j]时要调用f[j-v[i]],但在外循环为i层时 f[j-v[i]]在f[j]之前已经遍历过了,
且(f[j])更新为maxf[i][j-v[i]]而不再是maxf[i-1][j-v[i]],完全背包正好需要的是f[i][j-v[i]],所以完全背包正序遍历j。
当我们逆序遍历j时,我们遍历到f[j]时要调用f[j-v[i],而f[i][j-v[i]]还未被遍历,故f[j-v[i]]依然保存的是maxf[i-1][j-v[i]],因此逆序遍历适用于01背包。
语言组织不太行加上确实不太好表述,已经尽力了,希望对大家有帮助,也希望自己以后能看一看自己发的这第一篇文章