《算法导论》15章动态规划对这些要点都做了总结。
动态规划定义:https://zh.wikipedia.org/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92
把原问题分解为相对简单的子问题的方式求解复杂问题的方法,适用于有重叠子问题和最优子结构性质的问题。
动态规划与分治法的区别:http://jarg.iteye.com/blog/865117
总结起来,动态规划分解的子问题相互重叠(合并时不会影响其子问题的解,借用算法的稳定性这个概念,分解也需要是稳定的),分治法的子问题相互独立。能够用动态规划解决的问题也可已通过分治法解决,优化了实现策略,不去求解重复问题。
动态规划的本质:https://www.zhihu.com/question/23995189/answer/35429905
其核心是拆分,更官方的说法是,状态的定义和状态转移方程的定义。
有一种观点认为备忘或者记录不是动态规划方法的核心,我不这么认为,备忘或者记录正是体现分治的子问题相互重叠,是动态规划实现机制中的重要一步。
动态规划为什么叫动态规划:
随着问题规模的变化,问题的最优方案是动态变化的。如求解1,2,7,8,4,5,6……这个序列的最长上升子序列,
问题规模是4时(1,2,7,8)最优方案时1,2,7,8。问题规模时6时(1,2,7,8,4,5)最优方案为1,2,7,8或者1,2,4,5。当问题规模为7时(1,2,7,8,4,5,6)最优方案为1,2,4,5,6。最优方案一直是动态变化的。
应用动态规划方法的4个步骤
1.刻画一个最优解的结构特征;
2.递归地定义最优解的值;
3.计算最优解的值,通常采用自底向上的方法;
4.利用计算出的信息构造一个最优解
动态规划方法求解最优化问题的两个要素:最优子结构和子问题重叠
最优子结构:最优解包含其子结构的最优解。
子问题重叠:如果递归算法反复求解相同的子问题,我们说最优化问题具有重叠子问题 性质。
相关实例:钢条切割问题,矩阵链乘法,最长公共子序列
—————————————————————————————————————————————————————————————————
钢条切割问题:http://blog.csdn.net/luoshixian099/article/details/46334097
求长度n的最优切割方案(求解n=4)。
问题分析:长度为n的钢条,在n-1个位置选择切还是不切,共有2^(n-1)中方案。
递归方案的选择(a.规模减小;b.遍历;c.简洁):
设最佳收益为r[n],r[n]=max(p[n],r[1]+r[n-1],r[2]+r[n-2],……,r[n-1]+r[1]),最优方案:两个最优子方案之和的遍历。
更经典的方案:r[n]=max(p[i]+r[n-i]),1<=i<=n。最优方案:切一刀p[i]后,求剩下的r[n-i]的遍历。
常规的自顶向下递归实现:
CUT-ROD(p,n)//p是价格数组,n是钢条长度。
- if n==0
- return 0
- q=0//q 代表长度为n时的收益
- for i=1 to n
- {
- q=max(q,p[i]+CUT-ROD(p,n-i))
- }
- return q
假设n=4时,调用的递归树(CUT-ROD(p,n),中函数调用的次数为2^n)
动态规划问题求解这个问题
加入备忘机制的自顶向下方法
MEMOIZED-CUT-ROD(p,n)
- let r[0……n] be a new array
- for i = 0 to n
- {
- r[i]=-1
- }
- retrun MEMOIZED-CUT-ROD-AUX(p,n,r)
MEMOIZED-CUT-ROD-AUX(p,n,r)
- if r[n]>=0
- return r[n]
- if n==0
- {
- q=0
- }
- else
- {
- q=-FFFF
- }
- for i =1 to n
- {
- q=max(q.p[i]+MEMOIZED-CUT-ROD-AUX(p,n-i,r)
- }
- r[n]=q
- return q
自底向上的求解方法(并且记录切割方案)
EXTENDED-BOTTOM-UP-CUT-ROD(p,n)
- let r[0……n] and s[0……n] be new arrays
- r[0]=0
- for j = 1 to n
- {
- q = -FFFF
- for i = 1 to j
- {
- if q<p[i]+r[j-i]
- {
- q=p[i]+r[j-i]
- s[j]=i
- r[j]=q
- }
- }
- }
- return r and s