目录
- 设计思想
- 使用动态规划的必要条件
- 适用动态规划算法解决的问题的特征:
- 优化原则:
- 动态规划的一般步骤
- 以背包问题为例
动态规划本质上为带备忘录的穷举算法。对动态规划问题,直接套框架即可:问题有什么「状态」,有什么「选择」,然后穷举。
设计思想
动态规划算法适用于组合优化问题,通过划分子问题的边界,从子问题开始逐层向上求解,通过子问题之间的依赖关系进行推导计算,最大限度减少重复工作,提高算法效率。但需要较大的存储空间来存储子问题计算的中间结果。
使用动态规划的必要条件
使用动态规划的问题,必须满足优化原则
-
适用动态规划算法解决的问题的特征:
(1) 求解的问题是多阶段决策(优化)问题
(2)求解的过程是多步判断,从小到大依次求解每个子问题,最后求解的子问题即为原始问题
(3)子问题目标函数最优值之间存在依赖关系
(4)子问题符合「最优子结构」,即:子问题间必须互相独立。 -
优化原则:
一个最有决策序列的任何子序列本身一定是相对于子序列的初始和结束状态的最有决策序列
可以通俗理解为子问题间必须互相独立。
啥叫相互独立?你肯定不想看数学证明,我用一个直观的例子来讲解。
比如说,假设你考试,每门科目的成绩都是互相独立的。你的原问题是考出最高的总成绩,那么你的子问题就是要把语文考到最高,数学考到最高…… 为了每门课考到最高,你要把每门课相应的选择题分数拿到最高,填空题分数拿到最高…… 当然,最终就是你每门课都是满分,这就是最高的总成绩。
得到了正确的结果:最高的总成绩就是总分。因为这个过程符合最优子结构,“每门科目考到最高”这些子问题是互相独立,互不干扰的。
但是,如果加一个条件:你的语文成绩和数学成绩会互相制约,数学分数高,语文分数就会降低,反之亦然。这样的话,显然你能考到的最高总成绩就达不到总分了,按刚才那个思路就会得到错误的结果。因为子问题并不独立,语文数学成绩无法同时最优,所以最优子结构被破坏。
动态规划的一般步骤
明确「状态」 -> 定义 dp 数组/函数的含义 -> 明确「选择」-> 明确 base case。
-
首先要写出所求解的组合优化问题的目标函数和约束条件
-
确定子问题的结构和边界,将问题转化为多步判断的过程
-
确定问题是否满足优化原则
-
找出子问题之间的依赖关系(优化函数)
找状态转移需要归纳思维,说白了就是如何从已知的结果推出未知的部分,如假设已知dp[i-1] 如何推出dp[i] -
注意子问题的重叠程度,如果子问题重叠度较低,使用动态规划算法在时间复杂度上不会有较大改进
-
从初值开始自底向上计算子问题的优化函数值
以背包问题为例
问题描述:有编号分别为a,b,c,d,e的五件物品,它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,每件物品数量只有一个,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?
-
写出所求解的组合优化问题的目标函数和约束条件
设xi = 0|1
,当xi=0
表示第i
件物品不放入背包,1则表示放入
设vi
代表第i
件物品的价值,wi
代表第i
件物品的重量
原问题即为求一个xi
序列,使得总价V
最大且总量W<10
目标函数为:
max(∑xi∗vi)max(\sum xi*vi)max(∑xi∗vi)
约束条件为:
∑xi∗wi<=10\sum xi*wi <=10∑xi∗wi<=10 -
确定子问题的结构和边界,将问题转化为多步判断的过程
把原问题改为:当只能选择前i
件物品,背包容量为j
时,背包的最大价值,用dp[i][j]
表示。 -
确定问题是否满足优化原则
背包问题满足优化原则,证明过程省略… -
找出子问题之间的依赖关系(优化函数)
关系为:dp[i][j] = max(dp[i-1][j],dp[i-1][j-wi]+vi)
说明:
dp[i][j]
:当只能选择前i
件物品,且背包容量为j
时,背包的最大价值。
max(dp[i-1][j],dp[i-1][j-wi]+vi)
中dp[i-1][j]
表示不放入第i
件物品,dp[i-1][j-wi]+vi
表示为放入第i
件物品,腾出wi
的重量后获得的价值 -
从初值开始自底向上计算子问题的优化函数值
最后计算的子问题的解即为原始问题的解