背包问题可用这一套术语来定义:有一组想要带在身边的物品,每个物品都有各自的质量和价值。但问题是背包有一个最大容量,如何才能使其中所带物品的总价值达到最高呢?
选取一些元素组成一个带权值的有限子集,使其权值最大化。
无限制背包问题
当作一个模式来看待:以某种形式来定义问题的子问题,递归这些子问题之间的关系,然后确保每个子问题都只被计算一次。
围绕这背包容量中最后一个单元是否有用来进行。
def unbound_knapsack(weights, values, capacity):
res = [0]
for cu in range(1, capacity+1):
current = res[cu-1]
for wi, wu in enumerate(weights):
if wu > cu:
continue
current = max(current, values[wi]+res[cu-wu])
res.append(current)
return res[-1]
weights = [20, 10, 8]
values = [19, 31, 19]
capacity = 20
print(unbound_knapsack(weights, values, capacity)) # 62
0-1背包问题
每个对象最多只能用一次。
是否要纳入最后一个对象
def knapsack(weights, values, capacity):
n = len(weights)
res = [[0]*(capacity+1) for _ in range(n+1)]
flag = [[False]*(capacity+1) for _ in range(n+1)]
for nu in range(1, n+1):
for cu in range(1, capacity+1):
res[nu][cu] = pre = res[nu-1][cu]
if weights[nu-1] > cu:
continue
current = values[nu-1] + res[nu-1][cu-weights[nu-1]]
res[nu][cu] = max(pre, current)
flag[nu][cu] = current > pre
return res, flag
weights = [20, 10, 8]
values = [19, 31, 19]
capacity = 20
res, flag = knapsack(weights, values, capacity)
print(res[-1][-1]) # 50
wi, cur, items = len(weights), capacity, set()
while wi > 0 and cur > 0:
if flag[wi][cur]:
items.add(wi-1)
cur -= weights[wi-1]
wi -= 1
thing = {weights[i]: values[i] for i in items}
print(thing) # {10: 31, 8: 19}
(最近更新:2019年09月06日)