最近在学习动态规划问题,觉得很有意思,也很实用。把自己的想法和书上看到的知识分享下:
动态规划顾名思义,就是在不断的解决之前的子问题中,最后得到了大问题的解,有点像分治方法,都是通过组合子问题来求解原问题。动态规划就是在不断尝试中前行,在尝试中我们可以保存已经成功的子问题,类似于我们把成功的事情总结出了经验或定理供下次使用。
动态规划方法通常用来求最优化问题,注意可以取得最优,而贪心算法就不一定是最优的,当然有可能有多个最优解我们,我们找到的是一个最优解。
构造一个动态规划算法一般分为4个步骤:
1.刻画一个最优解的结构特征。 //分析阶段
2.递归的定义最优解的值 。 //分析阶段
3.计算最优解的值 //考虑实现
4.利用计算出的信息构造最优解 //考虑保存路径
以钢条切割为例,给定一个一段长度为n米的钢条和一个价格表Pi(i=1..n),求钢条切割方案,使得销售收益最大
有两种考虑方案:
1:完成钢条首次切割后,把钢条切割问题堪称连个独立的钢条切割问题,通过组合关于问题的最优解,并考虑所有可能的两段切割方案中选取组合收益最大者,就构成了原问题的最优解。
2.因为从左边切割下长度i的钢条(i在切割方案中,因为最后所有的切割结果都要按照切割出的i范围的大小出售,所以考虑左边所有的切割长度,即考虑了所有可能结果)
显然第二个方法更简单易行,注意:如果没有记录已经算出的问题会造成大量的重复计算,让时间复杂度变成n的指数级,记录自问题最优解可是时间复杂度在O(n^2)
这是典型的用空间换时间
自顶向下的递归实现,带备忘和和路径
memoized-cut-rod(p,n)
let r[0..n],s[0..n] be a new array
for i=0 to n
r[i] = -infinity
return memoized-cut-rod-aux(p,n,r,s)
memoized-cut-rod-aux(p,n,r,s)
if r[n]>=0
retrun r[n]
if n == 0
q = 0
else q=-infinity
for i =1 to n
q = max(p,p[i]+memoized-cut-rod-aux(p,n-i,r,s))
r[n]=q
s[n] = k
return q
至底向上非递归实现
</pre><pre class="html" name="code">extended-bottom-up-cut-rod(p,n)
let r[0..n],s[0..n] be a new array
r[i] = 0
for j=1 to n
q= -infinity
for i=1 to j
if q<p[i]+r[j-1]
q = p[i] =r[j-i]
s[j] = i
r[j] = q
return r and s
输出路径:
print-cut-rot-solution(p,n)
(r,s) = extended-bottom-up-cut-rod(p,n)
while n>0
print s[n]
n = n-s[n]