目录
一、博物馆大盗问题
大盗潜入博物馆, 面前有5件宝物, 分别有重量和价值, 大盗的背包仅能负重20公斤, 请问如何选择宝物, 总价值最高?
item | weight | value |
---|---|---|
1 | 2 | 3 |
2 | 3 | 4 |
3 | 4 | 8 |
4 | 5 | 8 |
5 | 9 | 10 |
【思路】
我们把
m
(
i
,
W
)
m(i, W)
m(i,W)记为:前
i
i
i
(
1
<
=
i
<
=
5
)
(1<=i<=5)
(1<=i<=5)个宝物中,组合不超过
W
W
W
(
1
<
=
W
<
=
20
)
(1<=W<=20)
(1<=W<=20) 重量,得到的最大价值。
当第
i
i
i件宝物的重量小于
W
W
W时,
m
(
i
,
W
)
m(i, W)
m(i,W)应该是不取第
i
i
i件
m
(
i
−
1
,
W
)
m(i-1, W)
m(i−1,W)和取第
i
i
i件
m
(
i
−
1
,
W
−
W
i
)
+
v
i
m(i-1, W-W_i)+v_i
m(i−1,W−Wi)+vi两者最大值
我们从
m
(
1
,
1
)
m(1, 1)
m(1,1)开始计算到
m
(
5
,
20
)
m(5, 20)
m(5,20)
n
u
m
C
o
i
n
s
=
{
0
,
i
f
i
=
0
0
,
i
f
W
=
0
m
(
i
−
1
,
W
)
,
i
f
w
i
>
W
max
{
m
(
i
−
1
,
W
)
,
v
i
+
m
(
i
−
1
,
W
−
w
i
)
}
,
o
t
h
e
r
w
i
s
e
numCoins= \begin{cases} 0, & if\text{ }i=0 \\ 0, & if\text{ }W=0 \\ m(i-1,W), & if\text{ }{{w}_{i}}>W \\ \max \{m(i-1,W),{{v}_{i}}+m(i-1,W-{{w}_{i}})\}, & otherwise \\ \end{cases}
numCoins=⎩⎪⎪⎪⎨⎪⎪⎪⎧0,0,m(i−1,W),max{m(i−1,W),vi+m(i−1,W−wi)},if i=0if W=0if wi>Wotherwise
【例】计算m(5,5),因为第五件的重量为9,大于5,因此m(5,5)=m(4,5),而第四件的重量为5,为分段函数中的第四种情况,其中取第四件的价值:m(3,0)+8 = 8,不取第四件的价值:m(3,5)=8
【代码:计算m(5,20)】
import numpy as np
#宝物的重量和价值
tr = [None,{'w':2,'v':3},{'w':3,'v':4},
{'w':4,'v':8},{'w':5,'v':8},
{'w':9,'v':10}]
max_w = 20 #最大承重
#初始化二维表格m存储value,bag存储所装宝物列表
#表示前i个宝物中,最大重量w的组合,所得到的最大价值
#当i什么都不取,或w上限为0,值均为0
bag = [[[] for col in range(max_w+1)] for row in range(len(tr))]
m = {(i,w):0 for i in range(len(tr)) for w in range(max_w+1)}
for i in range (1, len(tr)):
for w in range(1, max_w + 1):
if tr[i]['w'] > w: #装不下第i个宝物
m[(i,w)] = m[(i-1, w)]
bag[i][w].append(bag[i-1][w])
else: #不装第i个宝物,装第i个宝物,两种情况的最大值
m[(i,w)] = max(m[(i-1,w)],m[(i-1,w-tr[i]['w'])] + tr[i]['v'])
if (m[(i-1,w-tr[i]['w'])] + tr[i]['v'])>(m[(i-1,w)]):#装第i个宝物
bag[i][w].extend(bag[i-1][w-tr[i]['w']])
bag[i][w].append(tr[i]['w'])
else:#不装第i个宝物
bag[i][w].extend(bag[i-1][w])
print(m[(len(tr)-1,max_w)])
print("treasures are: ",bag[5][20])