动态规划的背包问题——01背包
挺简单的,与完全背包差不多,只不过是所有的物品可以随便选改为了每个物品只能选一次
状态设计(二维):设i为当前的物品,j为当前背包容量
转移方程为f(i,j)=max{f(i-1,j),f(i-1,j-w[i])+v[i]} 其中w[i]为当前物品的重量,v[i]为当前物品的价值
常规做法如下
for(int i=1;i<=n;i++)//物品数 { for(int j=0;j<=m;j++)//枚举容量 { if(j<w[i])//装不下肯定就不选 { f[i][j]=f[i-1][j]; } else//否则两种情况进行转移 { f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]); } } }
但这样空间复杂度为O(m*n),显然在m,n很大的情况下不得行
所以我们可以采取优化
我们看当前的最优解只与它的前一个有关,所以我们每次只更新这两个值即可
法1 滚动数组优化
int p=1,q=0;//只在这两行之间转移 for(int i=1;i<=n;i++) { for(int j=0;j<=m;j++) { if(j<w[i]) { f[p][j]=f[q][j]; } else { f[p][j]=max(f[q][j],f[q][j-w[i]]+v[i]); } } swap(p,q); //滚起来 }
法2 一维状态转移
通过观察还可以优化至一维f[n]表示当前容量下的最大值
for(int i=1;i<=n;i++) { for(int j=m;j>=w[i];j--) { f[j]=max(f[j],f[j-w[i]]+v[i]); } }
可是你就会发现枚举容量的时候要倒序,这是为什么呢?