动态规划-背包问题(上接递归)
[TOC]
动态规划:
- 动态规划算法采用了一种更有条理的方式来得到问题的解
 
- 找零兑换的动态规划算法从最简单的“1分钱找零”的最优解开始, 逐步递加上去, 直到我们需要的找零钱数
 
- 在找零递加的过程中, 设法保持每一分钱的递加都是最优解, 一直加到求解找零钱数, 自然得到最优解 
 
- 递加的过程能保持最优解的关键是, 其依赖于更少钱数最优解的简单计算, 而更少钱数的最优解已经得到了。
 
- 问题的最优解包含了更小规模子问题的最优解, 这是一个最优化问题能够用动态规划策略解决的必要条件 
 
博物馆大盗问题
大盗潜入博物馆, 面前有5件宝物, 分别有重量和价值, 大盗的背包仅能负重20公斤, 请问如何选择宝物, 总价值最高? 
| 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-W_i)+v_i$两者最大值
我们从$m(1, 1)$开始计算到$m(5, 20) $
博物馆大盗问题:动态规划表格
| m | 
0 | 
1 | 
2 | 
3 | 
4 | 
5 | 
… | 
| 0 | 
0 | 
0 | 
0 | 
0 | 
0 | 
0 | 
 | 
| 1 | 
0 | 
0 | 
3 | 
3 | 
3 | 
3 | 
 | 
| 2 | 
0 | 
0 | 
3 | 
4 | 
4 | 
7 | 
 | 
| 3 | 
0 | 
0 | 
3 | 
4 | 
8 | 
8 | 
 | 
| 4 | 
0 | 
0 | 
3 | 
4 | 
8 | 
8 | 
 | 
| 5 | 
0 | 
0 | 
3 | 
4 | 
8 | 
8 | 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
   |  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): 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:              m[(i, w)] = m[(i-1, w)]           else:                          m[(i, w)] = max(m[(i-1, w)], m[(i-1, w-tr[i]['w'])]+tr[i]['v'])
  print(m[(len(tr)-1, max_w)])
 
 
  | 
 
递归求解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
   |  tr = {(2, 3), (3, 4), (4, 8), (5, 8), (9, 10)}
  max_w = 20 m = {}
 
  def thief(tr, w):          if tr == set() or w == 0:         m[(tuple(tr),w)] = 0         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))
 
  |