描述
大盗潜入博物馆,面前有5件宝物,分别有重量和价值,大盗的背包仅能负重20斤,请问如何选择宝物,总价值最高?
对应关系如下:
宝物编号 | 重量 | 价值 |
---|---|---|
1 | 2 | 3 |
2 | 3 | 4 |
3 | 4 | 8 |
4 | 5 | 8 |
5 | 9 | 10 |
分析
设 v a l u e = f ( n , w ) value = f(n, w) value=f(n,w)为第n个宝物在w重量的限制下可以得到的最大价值,n(1<=n<=5)当前宝物个数,w(1<=w<=20)为所有宝物的重量。
通过 v a l u e = f ( n , w ) value = f(n, w) value=f(n,w)可以构建n行,m列的二维数据表,value便是表示当前组合的最大价值。
- 如果n或w有一个为0,那么value均为0;
- 如果第n个宝物的重量超过当前背包限制的重量,即装不下第n个宝物,最大价值value等于不装此宝物的价值,那么就等于第n-1个宝物在相同w的组合下产生的最大价值。
- 如果能装下第n个宝物,最大价值为max(不装第n个宝物的价值, 装下第n宝物的价值),装下第n宝物的价值 = f(宝物为第n-1件时and扣除当前宝物的重量限制的最大价值+当前这件宝物的价值)
- 扣除当前宝物的重量限制的最大价值的原因:第n个宝物放入后,背包的限制重量就需要减去第n个宝物的重量
- +当前这件宝物的价值:第n个宝物放入后,价值自然便计入当中
f ( n , w ) = { 0 if n = 0 o r w = 0 f ( n − 1 , w ) if w n > w m a x ( f ( n − 1 , w ) , f ( n − 1 , w − w n ) + v a l u e i ) if w n < w f(n, w) = \begin{dcases} 0 &\text{if } ~ n=0 ~~ or ~~ w=0 \\ f(n-1, w) &\text{if } ~ w_n > w \\ max(f(n-1, w), f(n-1, w-w_n) + value_i) &\text{if } ~ w_n < w \end{dcases} f(n,w)=⎩ ⎨ ⎧0f(n−1,w)max(f(n−1,w),f(n−1,w−wn)+valuei)if n=0 or w=0if wn>wif wn<w
代码
weight_value = [None,
{'w': 2, 'v': 3}, {'w': 3, 'v': 4},
{'w': 4, 'v': 8}, {'w': 5, 'v': 8}, {'w': 9, 'v': 10}]
max_weight = 20
values = {(n, w): 0 for n in range(len(weight_value)) for w in range(max_weight + 1)}
# 填写二维表格
for n in range(1, len(weight_value)):
for w in range(1, max_weight + 1):
# 如果装不下第n个宝物,最大价值等于不装此宝物的价值
if weight_value[n]['w'] > w:
values[(n, w)] = values[(n - 1, w)]
# 如果能装下第n个宝物,最大价值为max(不装此宝物的价值, 装此宝物的价值)
else:
# 装此宝物的价值=宝物为n-1件时and扣除当前宝物的重量限制的最大价值+当前这件宝物的价值
values[(n, w)] = max(values[(n - 1, w)], values[(n - 1, w - weight_value[n]['w'])] + weight_value[n]['v'])
if __name__ == '__main__':
print(values[(len(weight_value) - 1, max_weight)])
输出: 29
二维表明细
- f(5, 20)便是对应的最大价值