三类基础的背包问题
背包问题
最基础的背包问题包含以下三个子问题:
- 0-1背包问题:N个物品和一个容量为C的背包,第i件物品消耗的容量为\(C_i\),价值是\(W_i\),求放入哪些物品可以使得总价值\(V\)最大
- 完全背包问题:有N种物品和一个容量为C的背包,每种物品都有无限件可用,第i件物品消耗的容量为\(C_i\),价值为\(W_i\),求解放入哪些物品可以使得背包中总价值\(V\)最大
- 多重背包问题:有N种物品和一个容量为C的背包,第i种物品最多有\(M_i\)件可用,每件物品消耗的容量为\(C_i\),价值为\(W_i\),求解入哪些物品可以使得背包中总价值\(V\)最大。
这三种问题的相同之处就是:背包容量,背包的容量是一个有限的的数字,而我们需要在这个限制下找到可以使背包价值最大的方案。其中0-1背包是其他背包问题的基础,其他的问题都可以通过转换为0-1背包问题来解决。在完全背包问题中,虽然每种物品都可以选择无限个,但由于背包容量有限,实际上每种物品可以选择的数量也是有限的,那么将每种物品都看做是 V/Ci 种只有一件的不同物品,不就成了01背包问题吗?对于多重背包也是如此,只是每种物品的膨胀数量变成了 min{Mi, V/Ci}。
下面我们来看一下各个问题的状态转移方程:
状态转移方程
0-1背包问题
任何一个物品,都有装或者不装两个选项。如果我们装这个物品的话,那么背包剩余的容量减去这个物品消耗的容量;如果不装这个物品的话,背包剩余容量则不发生变化。同时,物品是否装入也会影响背包携带的物品的总价值。那么状态转移方程就如下所示:
其中V[i,j]
表示将前i
件物品装进限重为j
的背包可以获得的最大价值, 0<=i<=N, 0<=j<=C
V[i,j]=max(V[i-1,j],V[i-1,j-W[i]]+W[i])
完全背包问题
完全背包的状态转移方程如下所示:
V[i,j]=max(V[i-1,j-kCi] + kWi | 0 <= kCi <=j)
其中\(k\)是一个需要遍历的参数,表示装入的个数
多重背包问题
V[i,j]=max(V[i-1,j-kC[i]] + kW[i] | 0<=k<=M[i]&&0<=kC[i]<=j )
与完全背包类似,此时\(k\)依然是一个需要遍历的常数。另外需要同时满足:
- 装入的物品个数不可以超出背包的容量
- 装入的物品个数不可以超出物品本身的个数
这两个要求
伪代码(二维)
0-1背包问题
initial: V[0,:]=0,V[:,0]=0
for i=1:(n-1) :
for j=W[i]:(C-1):
V[i,j]=max(V[i-1,j],V[i-1,j-W[i]]+W[i] | j-W[i]>=0)
时间复杂度:O(cn)
空间复杂度:O(cn)
完全背包问题
initial: V[0,:]=0,V[:,0]=0
for i=1:(n-1) :
for j=W[i]:(C-1):
for k satisfy that 0 <= kC[i] <=j:
V[i,j]=max(V[i-1,j],V[i-1,j-kW[i]]+kW[i])
时间复杂度:O(kcn)
空间复杂度:O(kcn)
多重背包问题
initial: V[0,:]=0,V[:,0]=0
for i=1:(n-1) :
for j=W[i]:(C-1):
for k satisfy that 0 <= kC[i] <=j&&0<=k<=M[i]:
V[i,j]=max(V[i-1,j],V[i-1,j-kW[i]]+kW[i])
时间复杂度:O(kcn)
空间复杂度:O(kcn)