基本概念
在现实生活中,有一类活动的过程,由于它的特殊性,可将过程分程若干个互相联系的阶段,在它的每一阶段都需要作出决策,从而使整个过程达到最好的活动效果。当然,各个阶段决策的选取不是任意确定的,它依赖于当前面临的状态,又印象以后的发展,当各个阶段决策确定后,就组成一个决策序列,因而也就确定了整个过程的一条活动路线,这种把一个问题看作是一个前后关联具有连庄结果的多阶段过程就称为多阶段决策过程,这种问题就称为多阶段决策问题。
动态规划过程:每次决策依赖于当前状态,又随即引起状态的转义。一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就成为动态规划。
举例(一)
《算法导论》上面第一个讲解的动态规划问题就是Rod-Cutting 问题
Input: 有一个长n米的木头,和一个price table如下:
长度 i | 1 | 2 | 3 | 4 | 5 | 6 |
价格P[i] | 1 | 5 | 8 | 9 | 10 | 17 |
Output:找一个cut的方法,使最后赚的最多
递归解法
最简单的方法,遍历
假设P[i]代表长度为i的木头的价格,max_price代表最大的价格, x 代表一次切的米数
那么,如下递归肯定成立
def cut(table, l):
q = 0
if l <= 0:
return 0
# i 表示一次切的米数
for i in table.keys():
q = max(q, table[i] + cut(table, l - i))
return q
这是一个简单的递归,但是计算的重复度非常高,计算了大量的重复数据,经过我测试,就算l = 15
这个重复的数字都能让人做恶梦,重复了92167次
所以这只是一个暴力递归的解法
动态规划
回过头来,我们发现,cut(table, l - i)调用的次数太多了,我们完全可以建立一张表,来记录所有的max(q, table[i] + cut(table, l - i)) 这样,很多值就不用重新计算了,这就是动态规划的思路
代码如下:
def cut_dp(table, l):
r = [0] * (l + 1)
for i in range(1, l + 1):
q = 0
for j in table.keys():
q = max(q, table[j] + r[i - j])
r[i] = q
return r[l]
跟非动态规划的算法其实比较一致,只不过是计算时,将每次计算的最大值都记录到了表r中,这样就大大降低了迭代的次数。