目录
前言
一、动态规划是什么?
二、动态规划的适用条件
1.存在最优子结构
2.无后效性
3.子问题的重叠性质
?三、动态规划的解题思路
1.将原问题转化为若干个子问题
2.证明最优子结构
3.确定初始状态
4.确定状态转移方程
四、动态规划思路拓展——备忘录算法
1.什么是备忘录算法
2.备忘录方法的实现
五、动态规划的典型例题
1.最简单的dp——数字三角形问题
2.似曾相识的dp——最简单的最短路径算法
3.最经典的DP问题——01背包问题
4.最难的DP问题
总结
前言
动态规划是所有程序猿学习算法的过程中,所绕不开的一种解题方法。在此之前,我们喜欢使用暴力、暴搜(dfs)、贪心等算法来解决问题, 不巧的是,往往仅靠上述算法无法更好的解决更加广泛的问题,在某些问题中,单靠暴力解题往往会带了指数级的时间复杂度甚至O(n!)的时间复杂度,而此类题目采用动态规划算法可以将时间复杂度大幅度减少。现在,让我们进入正题。
一、动态规划是什么?
动态规划的定义:动态规划算法是通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推(或者说分治)的方式去解决。 动态规划算法的基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子问题,前一子问题的解为后一子问题的解提供一定的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的
局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是初始问题的解。
二、动态规划的适用条件
1.存在最优子结构
?如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质(即满足最优化原理)。最优子结构性质为动态规划算法解决问题提供了重要线索。其中全局最优解一定包含局部子问题的最优解。
2.无后效性
即子问题的解一旦确定,就不再改变,不受在这之后、包含它的更大的问题的求解决策影响。
3.子问题的重叠性质
子问题重叠性质。子问题重叠性质是指在用递归算法(如dfs)自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格中,当再次需要计算已经计算过的子问题时,只是在表格中简单地查看一下结果,从而获得较高的效率。
?三、动态规划的解题思路
1.将原问题转化为若干个子问题
把原问题分解为若干个子问题。子问题与原问题的结构、形式相同或类似,仅仅是规模变小了,子问题解决完成后,原问题也就得到了解决。同时,子问题的解一但求出就将其保存,每个相同子问题都只需要进行一次求解。
2.证明最优子结构
通过剪贴法证明该题目符合最优子结构的性质,然后进行判断子问题是否没有后效性,从而证明出可以通过动态规划的方法进行求解。
3.确定初始状态
确定原问题的规模,边界条件等限制因素。
4.确定状态转移方程
确定原问题中的“状态”是什么,以及找出原问题与子问题在该“状态”下的值,从而找出不同的状态之间如何进行转移。即如何从一个或多个已知“值”的状态,求出另一个状态的“值”。状态的转移过程可以用递推公式表示出来,因此递推公式也称作状态转移方程。
四、动态规划思路拓展——备忘录算法
1.什么是备忘录算法
(1)备忘录法是为了解决避免递归算法中相同子问题的重复求解。
(2)备忘录法为每个解过的子问题建立备忘录以备需要时查看,所以也称搜表法。
(3)备忘录法的控制与直接使用递归方法的控制结构相同。
(4)备忘录法又称记忆化搜索,自顶向下的方式解决问题。
由此可以发现,备忘录方法的递归方式是自顶向下的,动态规划算法是自底向上的,二者的主要区别在于备忘录方法将每一个子问题的解建立成了备忘录。
2.备忘录方法的实现
避免子问题重复被求解,我们可以定义一个数组,每次要计算一个子问题时,首先从数组中查询这个子问题的解,子问题解没有在数组中,说明没有计算过该子问题,我们可以计算该子问题,并将解放到数组中去,以便下次计算该子问题时,可以直接从数组中拿。
五、动态规划的典型例题
1.最简单的dp——数字三角形问题
数字三角形问题可以让我们更好的,更直观的看到动态规划的思路,大家做完这个题大概就知道什么是动态规划了,当然,做完这个题大家一定学不明白动态规划。
题目描述:给定一个如下图所示的数字三角形,从顶部出发,在每一节点可以选择移动至其左下方的节点或其右下方的节点,一直走到最底层,要求找到一条路径,使路径上的数字和最大。
思路:从倒数第二层开始,判断在倒数第二层每个点走到最后一层经过点数字和的最大值,并保存在该点对应的二维数组中,进而用同样的思想求倒数第三层,直到第一层。
题目链接:898. 数字三角形 - AcWing题库
在此不放具体的源码,而是为大家提供可以练习相关题目的OJ链接,大家可以自行完成题目并进行在线提交
2.似曾相识的dp——最简单的最短路径算法
大家是否还记的在学习数据结构时学习了三种最短路径的求法,Floyd算法,Dijkstra算法以及SPFA算法,其中Floyd算法就用到了动态规划的思想。不得不承认在求一个点对一个点的最短路径时Floyd算法的时间复杂度非常糟糕,但是在求多点对多点的问题中,floyd往往是一个简单而快捷的算法。
Floyd算法又称为插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似。该算法名称以创始人之一、1978年图灵奖获得者、斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名。
不具体展开说了,大家回忆回忆,我给大家看一下Floyd的核心代码的,大家应该就能明白了。
给大家一个相关问题,大家试试通过Floyd的算法能不能将其A出来~
题目链接:??????3556. 最短路径 - AcWing题库
3.最经典的DP问题——01背包问题
题目思路:0-1 背包问题的求解思路即是不断对第 i个物品做出决策,0、1分别代表不选与选两种决定。
(1)状态dp[i][j]的相关定义:对于前i个物品,背包容量 j 下的最大价值:
当前的状态依赖于之前的状态,可以理解为从初始状态dp[0][0] = 0开始决策,有N件物品,则需要 N次决策,每一次对第i件物品的决策,状态dp[i][j]不断由之前的状态更新而来。 (2)如果当前背包容量不够(j < w[i]),没得选,因此前i个物品最优解即为前i?1个物品最优解:对应代码:dp[i][j] = dp[i - 1][j]。 (3)如果当前背包容量够,可以选,因此需要决策选与不选第 i个物品:选:dp[i][j]=dp[i - 1][j - w[i]] + v[i]。 不选:dp[i][j] = dp[i - 1][j] 。 我们的决策是如何取到最大价值,因此以上两种情况取 max() 。
给大家一个相关问题,大家试试通过Floyd的算法能不能将其A出来~
题目链接:2. 01背包问题 - AcWing题库
4.最难的DP问题
接触的题目不多,其实我并不知道什么是最难的DP问题(感觉数位DP,状压DP都不简单),对于入门的同学来说,相信大家感觉DP的问题都不会特别简单,于是在这儿给大家提供几个简单的DP问题进行练习吧!
1.最长公共子序列问题?3510. 最长公共子序列 - AcWing题库
2.凸多边形三角划分问题? ?4028. 凸多边形三角剖分 - AcWing题库
4.矩阵链乘问题?矩阵链乘法 - NBUT 1003 - Virtual Judge
5.石子合并问题?282. 石子合并 - AcWing题库
6.上升子序列问题?272. 最长公共上升子序列 - AcWing题库
六.动态规划学习思维导图
总结
通过学习动态规划的特性及应用范围。掌握DP的基础知识,完成动态规划的入门。从而可以挑战更进一步难度的动态规划问题。
|