趣学算法之动态规划

简介: 趣学算法之动态规划

努力是为了不平庸~

算法知识点

动态规划算法的基本要素

(1)子问题重叠性质

每次产生的子问题并不总是新问题,有些子问题被反复计算多次,这种性质称为子问题重叠性质。动态规划算法对每一个子问题只解一次,而后将其解保存在一个表格(通常用二维数组)中,当再次需要解此子问题时,只是简单地用常数时间查看一下结果。

(2)最优子结构性质——用动态规划法求解的前提。

当一个问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质。

一个问题的活动过程可以分为若干个阶段,每个阶段可包含一个或多个状态,从初始阶段的初始状态出发做出每个阶段的决策,形成一个决策序列。

利用问题的最优子结构性质,以自底向上的方式递归地从子问题的最优解逐步构造出整个问题的最优解。

通常不同的子问题个数随问题的大小呈多项式增长。因此用动态规划算法只需要多项式级时间,从而获得较高的解题效率。

算法题目来源

求两个给定序列X和Y的最长公共子序列

算法题目描述

求两个给定序列X和Y的最长公共子序列

做题思路

用动态规划算法求解问题的步骤:

1、找出最优解的性质,并刻划其结构特征;

2、递归地定义最优解值;

3、自底向上求最优解值;

4、根据计算最优解值时得到的信息构造一个最优解(此步只在要求得到最优解时才需要做)。

动态规划法是一种求解最优化问题的重要算法策略。

模板代码

class LCS
{
public:
LCS(int nx,int ny,char *x,char *y);
//创建二维数组c、s和一维数组a、b,并进行初始化
int LCSLength();//求最优解值(最长公共子序列长度)
void CLCS();//构造最优解(最长公共子序列)
…….
private:
void CLCS (int i, int j);
int **c,**s,m,n;//c[i][j]中保存最优解值
char *a,* b;
};
int LCS::LCSLength()//求最长公共子序列的长度
{
for (int i=1; i<=m; i++) c[i][0]=0;
for (i=1; i<=n; i++) c[0][i]=0;
for (i=1; i<=m; i++)//逐行向下
for (int j=1; j<=n; j++)//从左至右扫描求值
if (x[i]==y[j])
{  c[i][j]=c[i-1][j-1]+1; s[i][j]=1;
//由c[i-1][j-1]计算c[i][j]}
else if (c[i-1][j]>=c[i][j-1]
{  c[i][j]=c[i-1][j]; s[i][j]=2;
//由c[i-1][j]得到c[i][j]}
else 
{  c[i][j]=c[i][j-1]; s[i][j]=3;
//由c[i][j-1]得到c[i][j]}
return c[m][n];//返回最优解值
}

做题过程中遇到的bug及解决方案

1、数组s可以省去

c[i][j]是由c[i][j]=c[i-1][j-1]+1,c[i][j]=c[i-1][j]或c[i][j]=c[i][j-1]计算得来的,要确定c[i][j]是从这三者中哪一个计算得来的,可以直接由c的值确定,而不必借助s。

因此可以写一个类似的CLCS算法在O(m+n)时间内构造最长公共子序列。

2、如果只需计算最长公共子序列的长度(而不用构造最优解),那么算法的空间需求还可以大大减少。

原因:计算c[i][j]仅用到第i行和第i-1行元素。因此只需两行元素空间就可以计算最长公共子序列的长度。

因此算法的空间复杂度为O(n)。

相关算法比较

动态规划法与分治法

共同点:

将待求解的问题分解成若干子问题,先求解子问题,然后再从这些子问题的解得到原问题的解。

不同点:

1、适合于用动态规划法求解的问题,分解得到的各子问题往往不是相互独立的;

而分治法中子问题相互独立。

2、动态规划法用表保存已求解过的子问题的解,再次碰到同样的子问题时不必重新求解,而只需查询答案,故可获得多项式级时间复杂度,效率较高;

而分治法中对于每次出现的子问题均求解,导致同样的子问题被反复求解,故产生指数增长的时间复杂度,效率较低。

动态规划法与贪心法

共同点:

都是求解最优化问题;都具有最优子结构性质。

不同点:

1、求解方式不同:

动态规划法:自底向上;

贪心法:自顶向下。以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为一个规模更小的子问题。

2、对子问题的依赖不同:

动态规划法:依赖于各子问题的解。只有在解出相关子问题后,才能作出选择;应使各子问题最优,才能保证整体最优;

贪心法:不依赖于子问题的解。仅在当前状态下作出最好选择,即局部最优选择。

扩展

备忘录方法

备忘录方法的控制结构与自顶向下直接递归方法的控制结构相同。

区别在于备忘录方法为每个已解过的子问题建立了备忘录进行保存,以备需要时直接查看,之后不再重复计算。是动态规划法的一种变形。

备忘录方法与动态规划法比较

1、与动态规划法的共同点:用一个表格来保存已求解的子问题的答案,使下次需要解此子问题时,只简单地查看答案,不重新计算。

2、与动态规划法的区别:备忘录的递归方式是自顶向下,而动态规划法的递归方式是自底向上。

备忘录方法与递归方法比较

1、与递归方法的共同点:递归方式均为自顶向下

2、与递归方法的区别:备忘录方法用一个表格来保存已求解的子问题的答案,使下次需要解此子问题时,只简单地查看答案,不重新计算;而递归方法在每次遇到子问题都要重新计算。

如何选择使用动态规划法或备忘录法?

当一个问题的所有子问题都至少要解一次时,选用动态规划法较好,此时没有任何多余的计算,还可利用规则的表格存取方式,减少时间和空间需求。

当一个问题只有部分子问题需要求解时,选用备忘录法较好,它只解那些确实需要求解的子问题。


目录
相关文章
|
3月前
|
存储 算法
深入了解动态规划算法
深入了解动态规划算法
89 1
|
3月前
|
算法 测试技术 C++
【动态规划算法】蓝桥杯填充问题(C/C++)
【动态规划算法】蓝桥杯填充问题(C/C++)
|
6月前
|
算法 开发者 Python
惊呆了!Python算法设计与分析,分治法、贪心、动态规划...这些你都会了吗?不会?那还不快来学!
【7月更文挑战第10天】探索编程巅峰,算法至关重要。Python以其易读性成为学习算法的首选。分治法,如归并排序,将大问题拆解;贪心算法,如找零问题,每步求局部最优;动态规划,如斐波那契数列,利用子问题解。通过示例代码,理解并掌握这些算法,提升编程技能,面对挑战更加从容。动手实践,体验算法的神奇力量吧!
78 8
|
6月前
|
算法 Python
算法不再难!Python分治法、贪心、动态规划实战解析,轻松应对各种算法挑战!
【7月更文挑战第8天】掌握Python算法三剑客:分治、贪心、动态规划。分治如归并排序,将大问题拆解递归解决;贪心策略在每步选最优解,如高效找零;动态规划利用子问题解,避免重复计算,解决最长公共子序列问题。实例展示,助你轻松驾驭算法!**
79 3
|
2月前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
67 2
|
3月前
|
算法
动态规划算法学习三:0-1背包问题
这篇文章是关于0-1背包问题的动态规划算法详解,包括问题描述、解决步骤、最优子结构性质、状态表示和递推方程、算法设计与分析、计算最优值、算法实现以及对算法缺点的思考。
131 2
动态规划算法学习三:0-1背包问题
|
3月前
|
算法
动态规划算法学习四:最大上升子序列问题(LIS:Longest Increasing Subsequence)
这篇文章介绍了动态规划算法中解决最大上升子序列问题(LIS)的方法,包括问题的描述、动态规划的步骤、状态表示、递推方程、计算最优值以及优化方法,如非动态规划的二分法。
86 0
动态规划算法学习四:最大上升子序列问题(LIS:Longest Increasing Subsequence)
|
3月前
|
算法
动态规划算法学习二:最长公共子序列
这篇文章介绍了如何使用动态规划算法解决最长公共子序列(LCS)问题,包括问题描述、最优子结构性质、状态表示、状态递归方程、计算最优值的方法,以及具体的代码实现。
201 0
动态规划算法学习二:最长公共子序列
|
3月前
|
存储 人工智能 算法
【算法——动态规划】蓝桥ALGO-1007 印章(C/C++)
【算法——动态规划】蓝桥ALGO-1007 印章(C/C++)
【算法——动态规划】蓝桥ALGO-1007 印章(C/C++)
|
3月前
|
存储 算法
动态规划算法学习一:DP的重要知识点、矩阵连乘算法
这篇文章是关于动态规划算法中矩阵连乘问题的详解,包括问题描述、最优子结构、重叠子问题、递归方法、备忘录方法和动态规划算法设计的步骤。
211 0

热门文章

最新文章

下一篇
开通oss服务