动态规划理解分析

动态规划

动态规划是一种通过“大而化小”的思路解决问题的算法,动态规划解决的是这些大而化小后变成的小问题是否被重复调用的问题。本质是对问题状态的定义 状态转移方程 的定义,过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推(或者说分治)的方式去解决。比较适用于有重叠子问题和最优子结构性质的问题。

  1. 最优子结构性质。如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质(即满足最优化原理)。最优子结构性质为动态规划算法解决问题提供了重要线索。
  2. 无后效性。即子问题的解一旦确定,就不再改变,不受在这之后、包含它的更大的问题的求解决策影响。
  3. 子问题重叠性质。子问题重叠性质是指在用递归算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格中,当再次需要计算已经计算过的子问题时,只是在表格中简单地查看一下结果,从而获得较高的效率。

于确定状态转移方程就在第一步和第二步中,首先要确定问题的决策对象,接着对决策对象划分阶段并确定各个阶段的状态变量,最后建立各阶段的状态变量的转移方程。

例如用dp[i]表示以序列中第i个数字结尾的最长递增子序列长度和最长公共子序列中用dp[i][j]表示的两个字符串中前 i、 j 个字符的最长公共子序列,我们就是通过对这两个数字量的不断求解最终得到答案的。这个数字量就被我们称为状态。状态是描述问题当前状况的一个数字量。首先,它是数字的,是可以被抽象出来保存在内存中的。其次,它可以完全的表示一个状态的特征,而不需要其他任何的辅助信息。最后,也是状态最重要的特点,状态间的转移完全依赖于各个状态本身,如最长递增子序列中,dp[x]的值由 dp[i](i < x)的值确定。若我们在分析动态规划问题的时候能够找到这样一个符合以上所有条件的状态,那么多半这个问题是可以被正确解出的。所以说,解动态规划问题的关键,就是寻找一个好的状态。

分治与动态规划

共同点:二者都要求原问题具有最优子结构性质,都是将原问题分而治之,分解成若干个规模较小(小到很容易解决的程序)的子问题.然后将子问题的解合并,形成原问题的解.

不同点:分治法将分解后的子问题看成相互独立的,通过用递归来做。

     动态规划将分解后的子问题理解为相互间有联系,有重叠部分,需要记忆,通常用迭代来做。

如何理解状态转移方程

不妨把状态转移方程理解为递归关系。就是如何从已知求得未知的表达式。
比如找一列数中最大的一个数,如果你知道了前n个数中最大,记做Max_n
那么当你遇到第n+1个数x_n+1的时候,前n+1个数中最大值是什么呢,就是拿这个新x去和之前那个max比,然后留下较大的一个,对吧,写下来就是
Max_n+1 = (x_n+1 > Max_n) ? x_n+1 : Max_n
这就是一个状态转移方程,就是一个递归关系。

即我们在知道了k阶段的状态和决策后就可以得到k+1阶段的状态。

1、最长公共子串

假设两个字符串为str1和str2,它们的长度分别为n和m。d[i][j]表示str1中前i个字符与str2中前j个字符分别组成的两个前缀字符串的最长公共长度。这样就把长度为n的str1和长度为m的str2划分成长度为i和长度为j的子问题进行求解。状态转移方程如下:

  1. dp[0][j] = 0; (0<=j<=m)
  2. dp[i][0] = 0; (0<=i<=n)
  3. dp[i][j] = dp[i-1][j-1] +1; (str1[i] == str2[j])
  4. dp[i][j] = 0; (str1[i] != str2[j])

因为最长公共子串要求必须在原串中是连续的,所以一但某处出现不匹配的情况,此处的值就重置为0。

详情解释过程参考:https://www.jianshu.com/p/096c945be66b

https://blog.csdn.net/hrn1216/article/details/51534607

2、最长公共子序列

区分一下,最长公共子序列不同于最长公共子串,序列是保持子序列字符串的下标在str1和str2中的下标顺序是递增的,该字符串在原串中并不一定是连续的。同样的我们可以假设dp[i][j]表示为字符串str1的前i个字符和字符串str2的前j个字符的最长公共子序列的长度。状态转移方程如下:

  1. dp[0][j] = 0; (0<=j<=m)
  2. dp[i][0] = 0; (0<=i<=n)
  3. dp[i][j] = dp[i-1][j-1] +1; (str1[i-1] == str2[j-1])
  4. dp[i][j] = max{dp[i][j-1],dp[i-1][j]}; (str1[i-1] != str2[j-1])

3、最大子序列和的问题

假设有序列{a1,a2,...,an},求子序列的和最大问题,我们用dp[i]表示以ai结尾的子序列的最大和。

dp[1] = a1; (a1>=0 && i == 1)

dp[i] = dp[i-1]+ai; (ai>=0 && i>=2)

dp[i] = 0; (dp[i-1] + ai <=0 && i>=2)

实际案例:

动态规划求解的一般思路

备忘录法

1.硬币找零

  扩展1:单路取苹果

  扩展2:装配线调度

2.字符串相似度/编辑距离(edit distance)

  应用1:子串匹配

  应用2:最长公共子序列

3.最长公共子序列(Longest Common Subsequence,lcs)

  扩展1:输出所有lcs

  扩展2:通过LCS获得最长递增自子序列

4.最长递增子序列(Longest Increasing Subsequence,lis)

  扩展:求解lis的加速

5.最大连续子序列和/积

  扩展1:正浮点数数组求最大连续子序列积

  扩展2:任意浮点数数组求最大连续子序列积

6.矩阵链乘法

  扩展:矩阵链乘法的备忘录解法(伪码)

7.0-1背包问题

8.有代价的最短路径

9.瓷砖覆盖(状态压缩DP)

10.工作量划分

11.三路取苹果
————————————————
参考:

https://cloud.tencent.com/developer/article/1086657

https://blog.csdn.net/txl199106/article/details/45318451

https://juejin.im/post/5d556b7ef265da03aa2568d5

分治法,动态规划,贪心算法的区别:
https://zhuanlan.zhihu.com/p/33048876

https://yq.aliyun.com/articles/284886

发布了29 篇原创文章 · 获赞 0 · 访问量 568

猜你喜欢

转载自blog.csdn.net/weixin_45632131/article/details/102808992
今日推荐