动态规划的背包问题——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]);
    }
}

可是你就会发现枚举容量的时候要倒序,这是为什么呢?

猜你喜欢

转载自www.cnblogs.com/LJB666/p/10806103.html