多重背包问题
如果每种物品有若干个,则是多重背包问题。
状态转移方程
假设第种物品有个可用,一种直观的思路是,把第种物品拆分成个物品,就转化成了了物品总数为的 0-1 背包问题。
按照该思路,状态转移方程为:
代码框架
伪代码如下:
f = [0] * (W+1)
for i in range(N):
for j in range(W, w[i]-1, -1):
K = min(j//w[i], c[i])
for k in range(1, K+1):
f[j] = max(f[j], f[j-k*w[i]] + k*v[i])
“拆分物品”还有更高效的拆分方法:把第 i
种物品拆分成k
个物品,系数分别为,其中 k
是满足 的最大整数。例如,某种物品有 13 个,即 c[i]=13
,则相应的 k=3
,这种物品应该被拆分成系数分别 1,2,4,6 的 4 种物品。这是二进制的思想,因为闭区间中的任何整数都可以表示为中若干个的和。
这样处理单个物品的复杂度由降到了,伪代码如下:
def bounded_knapsack(f: List[int], i: int):
if c[i]*w[i] >= W:
unbounded_knapsack(f, i)
return
k = 1
while k < c[i]:
zero_one_knapsack(f, i, k)
c[i] -= k
k *= 2
zero_one_knapsack(f, i, c[i])