注:不要随意复制代码,未运行过,就当做 伪代码 看看吧,有错误请留言
[TOC]
一. 引言
- 动态规划,Dynamic Programming;
programming指的是一种“表格法” - 与分治算法DC的异同
- 同:都是通过 “组合子问题的解” 来求解原问题
- 异:对于每个子子问题的处理不同 —— DP只处理一次,并将其解保存在一个表
格中。而DC没有考虑过子子问题的求解是否重复,DC更适用于互不相交的子问题
- DP设计步骤:
回头再看看
- 刻画一个最优解的结构特征
- 递归地定义最优解的值
- 计算最优解的值,通常“自底向上”
- 利用计算出的信息,构造一个最优解
二. 钢条切割问题
Serling公司购买长钢条,将其切割为短钢条出售。切割工序本身没有成本支出。公司管理层希望知道最佳的切割方案。假定我们知道Serling公司出售一段长为i英寸的钢条的价格为pi(i=1,2,…,单位为美元)。钢条的长度均为整英寸。
长度i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
价格pi | 1 | 5 | 8 | 9 | 10 | 17 | 17 | 20 | 24 | 30 |
钢条切割问题是这样的:给定一段长度为n英寸的钢条和一个价格表pi(i=1,2,…n),求切割钢条方案,使得销售收益rn最大。注意,如果长度为n英寸的钢条的价格pn足够大,最优解可能就是完全不需要切割。
1. 一般的递归算法 O(2n)
int cutRod(int* price, int length)
{
int maxP = 0;
if(length == 0)
return 0;
for(int i = 0; i < length; i++)
{
maxP = max(maxP,
price[i] + cutRod(price + i +1, length - i));
}
return maxP;
}
2. 动态规划方法求解 O(n2)
2-1. 带备忘的自顶向下法(top-down with memorization)
- 创建一个数组或散列表 r[length] ,代表长度为length时的最优解,全部初始化为-1。
- 在上面的基线条件之前,加入一个判断 r[length]>=0 即可,若true则直接return r[length]
2-2. 自底向上(bottom-up method)
- 不需要递归,变成了两个嵌套的for循环
int cutRod(int* price, int length)
{
int r[length + 1]; //这里存在一个问题,可能无法用变量定义数组长度,可改为链表或hash表。r[0]到r[length]。
r[0] = 0;
for(int i = 1; i <= length; i++)
{
int maxP = -1;
for(int j = 1; j <= i; j++)
maxP = max(maxP, price[j] + r[i - j]);//因为 i - j <= i - 1,所以一定已经计算过r[i - j]了。r[i - j]是对应长度i-j的最优解,所以只需分成price[j] 与 r[i - j]这两部分即可
r[i] = maxP;
}
return r[length];
}
三. 矩阵链乘法
1. 相关概念
- 完全括号化的(fully parent thesized):矩阵乘法满足结合律,由括号完全确定一个矩阵链的相乘顺序
- 相容(compatible): Ap∗q 与 Bq∗r 相容,即可以相乘
2. 矩阵链乘法问题(matrix-chain multiplication problem)——描述
给定
n
个矩阵的链<
3. 寻找最优括号化方案——最优解
- 暴力解:穷举
递归公式略(P221),方案数量与 n 成指数关系 动态规划方法
- 寻找最优子结构。从子问题的最优解,逆向构造出,原问题的最优解。(递归思想)
本题中:找到一个k将区间 [i,j] 分割为两部分,将Ai⋅⋅⋅Aj 括号化为 (Ai⋅⋅⋅Ak)(Ak+1⋅⋅⋅Aj) ,此时k为最优分割点,使得计算次数最小。 - 子问题重叠性质。自底向上:第一步就求出所有最小子问题,然后遵循上一步操作即可。
本题中:按顺序依次求 所有 2矩阵组、3矩阵组、4矩阵组 … n矩阵组的计算次数,小组是大组的子问题,可直接调用。 - 本题解法与时间复杂度
- 3个for循环:1.矩阵链长度length由小到大;2.一定长度下,“window slide”向右滑动,得到所有长度为length的小矩阵链;3.对于当前的小矩阵链,从i到j遍历,找到最佳分割点k∈[i, j)。伪代码见P213
- O(n3)
- 寻找最优子结构。从子问题的最优解,逆向构造出,原问题的最优解。(递归思想)
四. 动态规划原理总结
满足用 动态规划 求解 最优化 问题的两要素:最优子结构
、子问题重叠
1. 最优子结构
- 最优子结构性质:一个问题的最优解,包含其子问题的最优解
- 子问题无关性质:子问题不相交
2. 重叠子问题
递归算法反复求解相同的子问题时,称该最优化问题具有重叠子问题性质
3. 重构最优解
根据额外维护的表,重构。
4. 备忘
自顶向下方法 = 递归算法 + 备忘机制
有递归调用的开销
注:一般使用自底向上方法,不需要备忘,但也需要维护一个类似的表