背包问题(一):01背包问题

1.问题

  有 N N N件物品和一个容量为 V V V的背包。放入第 i i i件物品消耗容量为 v i v_i vi,得到的价值为 w i w_i wi。求背包总价值最大值。

2.基本思路

  问题特点:每个特点仅有一件,可以选择放或不放
  用子问题定义状态: F [ i , v ] F[i,v] F[i,v]表示前 i i i个物品放入一个容量为 v v v的背包可以获得的最大价值。状态转移方程为:
F [ i , v ] = m a x { F [ i − 1 , v ] , F [ i − 1 , v − C i ] + W i } (1) F[i,v]=max\{F[i-1,v],F[i-1,v-C_i]+W_i\}\tag{1} F[i,v]=max{F[i1,v],F[i1,vCi]+Wi}(1)
即对第i个物品有两种选择:
(1)不放入包中,则 F [ i , v ] = F [ i − 1 , v ] F[i,v]=F[i-1,v] F[i,v]=F[i1,v]
(2)放入包中,则 F [ i , v ] = F [ i − 1 , v − C i ] + W i F[i,v]=F[i-1,v-C_i]+W_i F[i,v]=F[i1,vCi]+Wi,即前 i − 1 i-1 i1个物品放入容量为 v − C i v-Ci vCi的背包的最大价值加上第 i i i个物品的价值;
  边界条件 F [ 0 , 0... V ] = 0 F[0,0...V]=0 F[0,0...V]=0,即没有物品放入,获得的最大价值为零。
  结果 F [ N , V ] F[N,V] F[N,V]
  遍历方向:由状态转移方程可知, F [ i , v ] F[i,v] F[i,v] F [ i − 1 , v ] F[i-1,v] F[i1,v] F [ i − 1 , v − C i ] F[i-1,v-C_i] F[i1,vCi]有关,即与第 i − 1 i-1 i1行有关,因此遍历方向为从上到下。
伪代码

F [ 0 , 0... V ] ← 0 f o r   i ← 1 t o    N f o r   v ← C i   t o   V F [ i , v ] = m a x { F [ i − 1 , v ] , F [ i − 1 , v − C i ] + W i } F[0,0...V]\leftarrow 0\\ for \ i \leftarrow 1 to \ \ N\\ \qquad \qquad for \ v \leftarrow C_i \ to \ V \\ \qquad \qquad \qquad \qquad\qquad\qquad\qquad\qquad\qquad\qquad F[i,v]=max\{F[i-1,v],F[i-1,v-C_i]+W_i\} F[0,0...V]0for i1to  Nfor vCi to VF[i,v]=max{F[i1,v],F[i1,vCi]+Wi}
时间复杂度:O(VN)
空间复杂度:O(VN)

3.空间复杂度优化

  上面提到的变量方向是从上向下,那么左右呢?无论从左向右还是从右向左似乎都可以完成任务,但要进行空间优化,需要进一步分析。
(1)从左向右
  若使用 F [ i , C i ] F[i,C_i] F[i,Ci]覆盖 F [ i − 1 , C i ] F[i-1,C_i] F[i1,Ci],则当计算 F [ i , 2 C i ] F[i,2C_i] F[i,2Ci]时,原来的 F [ i − 1 , C i ] F[i-1,C_i] F[i1,Ci]被覆盖,会出现错误;
在这里插入图片描述
(2)从右向左
  若从右向左更新,被更新的位置不会在本次遍历中再次使用,因此从右向左遍历可以优化空间复杂度。
在这里插入图片描述

伪代码
F [ 0... V ] ← 0 f o r   i ← 1   t o    N f o r   v ← V   t o   C i F [ v ] = m a x { F [ v ] , F [ v − C i ] + W i } F[0...V]\leftarrow 0\\ for \ i \leftarrow 1 \ to \ \ N\\ \qquad \qquad for \ v \leftarrow V \ to \ C_i \\ \qquad \qquad \qquad \qquad\qquad\qquad\qquad\qquad F[v]=max\{F[v],F[v-C_i]+W_i\} F[0...V]0for i1 to  Nfor vV to CiF[v]=max{F[v],F[vCi]+Wi}

时间复杂度:O(VN)
空间复杂度:O(V)

4.初始化细节

  问题分为两种:

(1)背包恰好装满: F [ 0 ] = 0 , F [ 1... N ] = − ∞ F[0]=0,F[1...N]=-\infin F[0]=0,F[1...N]=
(2)背包不用装满: F [ 0... V ] = 0 F[0...V]=0 F[0...V]=0
如何理解
  回到二维空间考虑, F [ 0 , 0... V ] F[0,0...V] F[0,0...V]的含义是前0个物品装 0... V 0...V 0...V容量背包能够获得的最大值。若要求恰好装满,除 F [ 0 , 0 ] F[0,0] F[0,0]外,其余的 F [ 0 , 1... V ] F[0,1...V] F[0,1...V]不满足“恰好”定义,背包价值没有意义;若不用装满, F [ 0 , 0... V ] F[0,0...V] F[0,0...V]可以什么都不装,最大价值为零。两者的区别在于边界条件是否有意义。

5.常数优化

  内循环的下限可以进行优化:
f o r   v ←   V   t o   C i ⟶ f o r   v ←   V   t o   m a x ( V − ∑ j = i N C j , C i ) for \ v \leftarrow \ V \ to \ C_i \qquad\longrightarrow \qquad\qquad for \ v \leftarrow \ V \ to \ max(V- \sum\limits_{j=i}^{N}{C_j},C_i) for v V to Cifor v V to max(Vj=iNCj,Ci)

如何理解
  首先看原来的下限是如何得到的:
  在内循环中,我们要保证装第 i i i个物品前背包至少有 C i C_i Ci的余量,即背包容量的最小值为 C i C_i Ci,这也就是内循环的下限。如果将其余的物品全部装完还至少有 C i C_i Ci的余量,则可以将下限提升到装完其余物品后的余量 V − ∑ j = i N C i V-\sum\limits_{j=i}^{N}{C_i} Vj=iNCi。常数优化在 V V V较大时效果较好,可以利用前缀和快速计算求和,避免重复计算。

参考链接:
背包九讲

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值