01背包&&完全背包优化问题(有图有真相) 新手入门必备

01背包&&完全背包优化问题(有图有真相)

01背包优化讲解

明白了 f [ i ] [ j ] f[i][j] f[i][j] 的含义之后,我们可以将01背包的状态转移方程写成:

f [ i ] [ j ] = m a x ( f [ i − 1 ] [ j ] , f [ i − 1 ] [ j − v [ i ] ] + w [ i ] ) f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]) f[i][j]=max(f[i1][j],f[i1][jv[i]]+w[i])

那么我们可以画一个矩阵来分析


图1

蓝色: f [ i ] [ j ] f[i][j] f[i][j]

黄色: f [ i − 1 ] [ j ] f[i-1][j] f[i1][j]

绿色: f [ i − 1 ] [ j − v [ i ] ] f[i-1][j-v[i]] f[i1][jv[i]]

f [ i ] [ j ] = m a x ( f [ i − 1 ] [ j ] , f [ i − 1 ] [ j − v [ i ] ] + w [ i ] ) f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]) f[i][j]=max(f[i1][j],f[i1][jv[i]]+w[i])

我们可以由👆的状态转移方程和👆的图1得到 f [ i ] [ j ] f[i][j] f[i][j] 只需要上一行的数据,而且是左上。(也就是 $蓝色 = 黄色+绿色 $ ) 那么我们可以把二维的矩阵优化成为一维数组,所以我们只需要用到 j j j ,此时我们将方程写出来: f [ j ] = m a x ( f [ j ] , f [ j − v [ i ] ] + w [ i ] ) f[j]=max(f[j],f[j-v[i]]+w[i]) f[j]=max(f[j],f[jv[i]]+w[i])

我们可以观察未进行空间优化的代码

我们的 f [ i ] [ j ] f[i][j] f[i][j] 只需要左上的数据,如果我们让 j j j 递增的遍历,那么我们除了用到了 f [ i − 1 ] [ j ] f[i-1][j] f[i1][j] 而且还用到了同一层 f [ i ] [ j − v [ i ] ] f[i][j-v[i]] f[i][jv[i]]

然而状态方程 : f [ i ] [ j ] = m a x ( f [ i − 1 ] [ j ] , f [ i − 1 ] [ j − v [ i ] ] + w [ i ] ) f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]) f[i][j]=max(f[i1][j],f[i1][jv[i]]+w[i]) 我们需要的是上一层的数据。

所以如果我们让 j j j 递减的遍历,那么我们用到的就是上一层 i − 1 i-1 i1 j j j 往左的数据了。

for(int i=1;i<=n;i++) 
{
	for(int j=v[i];j>=m;j++)
	{
        
        /* 未进行空间优化的代码
        for(int j=0;j<=m;j++)
        {
			f[i][j]=f[i-1][j];
			if(j>=v[i])
			f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);  
		}
		*/
        
        f[j]=max(f[j],f[j-v[i]]+w[i]);
	}
}

return f[m];

完全背包优化讲解

知道了01背包的优化方法之后,我们可以类比来看完全背包

状态转移方程 f [ i ] [ j ] = m a x ( f [ i − 1 ] [ j ] , f [ i ] [ j − v [ i ] + w [ i ] ) f[i][j]=max(f[i-1][j],f[i][j-v[i]+w[i]) f[i][j]=max(f[i1][j],f[i][jv[i]+w[i]) 其实除了直接用数学归纳法从三个for循环优化到两个for循环,还是可以直接从状态表示来理解。 f [ i ] [ j − v [ i ] ] + w [ i ] f[i][j-v[i]]+w[i] f[i][jv[i]]+w[i] :我们在取了许多物品之后,在体积不超过 j j j 的情况下再添加一件 i i i 物品和 f [ i − 1 ] [ j ] f[i-1][j] f[i1][j] 进行比较,取一个 m a x max max

让我们再看一下👇的图2:

蓝色: f [ i ] [ j ] f[i][j] f[i][j]

黄色: f [ i − 1 ] [ j ] f[i-1][j] f[i1][j]

红色: f [ i ] [ j − v [ i ] ] f[i][j-v[i]] f[i][jv[i]]


图2

优化一层空间 f [ j ] = m a x ( f [ j ] , f [ j − v [ i ] ] + w [ i ] ) f[j]=max(f[j],f[j-v[i]]+w[i]) f[j]=max(f[j],f[jv[i]]+w[i]) 而且我们从01背包问题中可以类比得,在完全背包问题中我们需要的是同一层的数据,所以我们需要让 j j j 从小到大递增遍历,这个时候我们用到的就是同一层 i i i 的数据了。

for(int i=1;i<=n;i++)
for(int j=v[i];j<=m;j++)


/* 1.可以优化一层for循环
for(int k=0;k*v[i]<=j;k++)
f[i][j]=max(f[i][j],f[i-1][j-v[i]*k]+w[i]*k;
*/

/* 2.可以优化一层空间
f[i][j]=max(f[i][j],f[i][j-v[i]+w[i]);
*/

f[j]=max(f[j],f[j-v[i]]+w[i]);

cout<<f[m];
蒟蒻语文不大好,算法也不大彳亍,尽量写了,希望能看得懂吧。。。
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值