背包问题总结

背包问题

 

背包问题 (Knapsack problem x ) 有很多种版本,常见的是以下三种:

  • 0-1 背包问题 (0-1 knapsack problem):每种物品只有一个
  • 完全背包问题 (UKP, unbounded knapsack problem):每种物品都有无限个可用
  • 多重背包问题 (BKP, bounded knapsack problem):第 i 种物品有 n[i] 个可用

 

0-1 背包问题

0-1背包中一种物体只有一个,放入数量为0或者1

定义状态 dp[i][j],表示“把前 i 种物品装进重量限制为 j 的背包可以获得的最大价值”

v[i]表示物品i的价值,w[i]表示物品i的重量,j为背包的重量限制

0/1背包问题状态转移方程便是:

   dp[i][j] = max{dp[i − 1][j],  dp[i − 1][j − w[i]] + v[i]}

    两项分别代表物品i不选择或者选择的情况 (减去的代表选择的)

时间复杂度是O(nb),空间也是O(nb),假设有n种物品,重量限制为b

 

 

可以简化为:

   d[j]=max{d[j],d[j-w[i]]+v[i]};

注意:遍历j时务必从右到左,因为d[j]只依赖于上一阶段的结果,从右到左避免覆盖上阶段有用结果

 

 

完全背包问题

完全背包中一种物体可以有多个,可以放满背包为止

完全背包问题状态转移方程是:

   dp[i][j] = max{dp[i − 1][j],  dp[i][j − w[i]] + v[i]}

两项分别代表物品i不选择或者选择,由于对物品i没有限制,故后一项为dp[i]而非上面的dp[i-1]

 

或用以下递推式(上面的效率要高一点):

dp[i][j] = max( dp[i-1][j-k*w[i]] + k*v[i] ), 

基于前i-1个物品,在选择不同个数的物品i的方案中选择最大的那个

(和问题coin change 比较相似)

 

可以简化为:

   d[j] = max{d[j], d[j-k*w[i]] + k*v[i]}

注意:遍历j时务必从右到左,原因同上

 

多重背包问题

多重背包中一种物体可以有多个,个数有人为限定(也不能超过背包容量)

多重背包问题状态转移方程是:

dp[i][j] = max( dp[i−1][j−k∗w[i]] + k∗v[i] )    0 ≤ k ≤ n[i],0 ≤ k ∗ w[i] ≤ j

n[i]为物品i限制的个数

基于前i-1个物品,在选择不同个数的物品i的方案中选择最大的那个

 

可以简化为:

   d[j] = max{d[j], d[j-k*w[i]] + k*v[i]}

注意:遍历j时务必从右到左,原因同上