注:本文如涉及到代码,均经过Python 3.7实际运行检验,保证其严谨性。

本文阅读时间约为8分钟。

博物馆大盗问题

大盗潜入博物馆,面前有5件不同的宝物,每件宝物都分别有自己的重量和价值。大盗的背包仅能负重20KG,请问如何选择某几件宝物,使得总价值最高?

宝物item 重量weight 价值value

1 2 3

2 3 4

3 4 8

4 5 8

5 9 10

分析:

贪心策略在这里是失效的,要解决问题,只能依靠动态规划。

创建一个函数m(i, w),这个函数表示的是,前i(1 <= i <= 5)个宝物中,组合不超过W(1 <= w <=20)重量,得到的最大价值。

m(i, w)应该是m(i-1, w)和m(i-1, w-wi)+vi两者的最大值(wi和vi中的i都是右下标)。

我们从m(1, 1)开始计算到m(5, 20),m(i, w)会有以下4种情况:

m(i, W)= { 0 if i = 0

0 if W = 0

m(i-1, w) if wi > w ……(wi中的i为w的右下标)

max{m(i-1, w), vi + m(i-1, w-wi)} otherwise ……(wi中的i为w的右下标)}

上述4种情况中,最关键的是在最后一种情况,max()函数的结果即是我们所求。

动态规划表格

根据上述分析,我们可以构建一个经过for i in range(1, 6)和for w in range(1, 21)双重遍历包含所有可能情况的这么一个表格。上节我们说过,问题的最优解包含了更小规模子问题的最优解,这是一个最优化问题能够用动态规划策略解决的必要条件。现在,我们具备了这个必要条件。


Pic-412-1 博物馆大盗问题的动态规划表格

按照上述思路,动态规划算法的程序代码如下:

# 动态规划算法解决博物馆大盗问题。

# 宝物的重量和价值,以字典形式展现。

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[(i, w)]

# 表示前i个宝物中,最大重量w的组合,所得到的最大价值。

# 当i什么都不取,或w上限为0,价值均为0。

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)] # 不装第i个宝物。

else:

# 不装第i个宝物,装第i个宝物,这两种情况下取最大值。

m[(i, w)] = max(m[i, w], m[(i - 1, w - tr[i]['w'])] + tr[i]['v'])

# 输出结果。

print(m[(len(tr)-1, max_w)])

<<<29

递归算法解决博物馆大盗问题

我们也可以用递归算法来解决博物馆大盗问题:

# 递归算法解决博物馆大盗问题。

# 宝物的重量和价值,以元组形式展现。

tr = {(2, 3), (3, 4), (4, 8), (5, 8), (9, 10)}

# 大盗背包的最大负重。

max_w = 20

# 初始化记忆化表格m。

# key是(宝物组合, 最大重量),value是最大价值。

m = {}

def thief(tr, w):

if tr == set() or w == 0:

m[(tuple(tr), w)] = 0 # tuple是key的要求。

return 0

elif (tuple(tr), w) in m:

return m[(tuple(tr), w)]

else:

vmax = 0

for t in tr:

if t[0] <= w:

# 逐个从集合中去掉某个宝物,递归调用。

# 选出所有可能的价值中的最大值。

v = thief(tr-{t}, w-t[0]) + t[1]

vmax = max(vmax, v)

m[(tuple(tr), w)] = vmax

return vmax

print(thief(tr, max_w))

<<<29

上面分别用动态规划和递归解决了博物馆大盗问题。动态规划当然能解决这类问题,但是,递归算法更符合人的直观思维,只要加上应用得当的记忆化,同样也能高效解决此类问题。

To be continued.