动态规划(dynamic programming)及示例(矩阵连乘、最长公共子序列、三角剖分)
2017-02-25 13:33
225 查看
动态规划是一个比较重要的算法思想,只要学了算法相关课程,一定会有这一章节。我会介绍动态规划的主要思想,也会在后面用Java实现几个经典算法(矩阵连乘、最长公共子序列、多边形三角剖分)作为示例加深理解。
动态规划通常用来解决最优化问题(optimization problem)。通常有4个步骤(先粗略看一下,了解了示例后再返回来看):
刻画一个最优解的结构特征;
递归地定义最优解地值;
计算最优解地值,通常采用自底向上地方法;
利用计算出的信息构造一个最优解。
例如,A1为 10*100 的矩阵,A2为100*5 的矩阵,A3为 5*50 的矩阵
((A1*A2)A3) )的复杂度:10*100*5+10*5*50=7500
(A1(A2*A3))的复杂度:100*5*50+10*100*50=750000
两种顺序计算复杂度大不相同。
要解决这一问题,最易想到的方法是穷尽所有可能,然后找出最小的,可是下图给出这种方法的计算复杂度(太大不可行):
但是经过分析,我们发现,这一问题(同时也是所有动态规划问题)有两个特点:
1.最优子结构:假设最后一个顺序是这样的(A1*A2 … AK)(AK+1* … * AN) , 那么(A1*A2 … AK) 和(AK+1* … * AN>)的最优顺序跟(A1-AN)相应顺序是一样的;
2.重复子问题:假设我们用分治法,自顶向下解决的话,会有一些子问题是重复的(所以才有优化空间);如图
根据最优子结构特征,我可以得到如下复杂度递归式:
式中 m[I,j]表示Ai到Aj 的最小相乘复杂度。 那么我们写出递归式以后就直接写递归算法去解决了吗?并不可以,因为递归解决的话重复子问题实际是重复计算了的
所以要自底向上,如图我们要求m[1,5]的话,先算斜边的m[1,1] … m[5,5] 再算m[1,2] … m[4,5]最后就得到m[1,5]:
代码如下,用java完成,同时也记录了切分点。
精力所限,马上没有时间去实现凸多边形三角剖分跟最长公共子序列了,以后有时间会实现,我现在给一个链接,写得不错,可以作为参考。
动态规划通常用来解决最优化问题(optimization problem)。通常有4个步骤(先粗略看一下,了解了示例后再返回来看):
刻画一个最优解的结构特征;
递归地定义最优解地值;
计算最优解地值,通常采用自底向上地方法;
利用计算出的信息构造一个最优解。
矩阵连乘
问题描述:
给定一个n个矩阵地序列(矩阵链)<A1,A2, ... ,AN>,我们希望计算他们的乘积 A1*A2* ... *AN 。 计算这样一个式子可以有不同相乘顺序,而且计算复杂度也不尽相同,我们希望找到复杂度最小的相乘顺序。
例如,A1为 10*100 的矩阵,A2为100*5 的矩阵,A3为 5*50 的矩阵
((A1*A2)A3) )的复杂度:10*100*5+10*5*50=7500
(A1(A2*A3))的复杂度:100*5*50+10*100*50=750000
两种顺序计算复杂度大不相同。
要解决这一问题,最易想到的方法是穷尽所有可能,然后找出最小的,可是下图给出这种方法的计算复杂度(太大不可行):
但是经过分析,我们发现,这一问题(同时也是所有动态规划问题)有两个特点:
1.最优子结构:假设最后一个顺序是这样的(A1*A2 … AK)(AK+1* … * AN) , 那么(A1*A2 … AK) 和(AK+1* … * AN>)的最优顺序跟(A1-AN)相应顺序是一样的;
2.重复子问题:假设我们用分治法,自顶向下解决的话,会有一些子问题是重复的(所以才有优化空间);如图
根据最优子结构特征,我可以得到如下复杂度递归式:
式中 m[I,j]表示Ai到Aj 的最小相乘复杂度。 那么我们写出递归式以后就直接写递归算法去解决了吗?并不可以,因为递归解决的话重复子问题实际是重复计算了的
所以要自底向上,如图我们要求m[1,5]的话,先算斜边的m[1,1] … m[5,5] 再算m[1,2] … m[4,5]最后就得到m[1,5]:
代码如下,用java完成,同时也记录了切分点。
public class Matrix_Chain_Order { public static void main(String[] args) { int[] p={30,35,15,5,10,20,25};//用一个数组表示各个矩阵的维度,7个数字代表6个数组相乘 int[][] m=new int[7][7];//二维数组存储m[i,j], 为了表示方便我用了7维数组,实际6维就足够了 //初始化时矩阵里都为零,所以像m[1,1] m[2,2]就不用置零了。 int[][] mark=new int[7][7];//存储切分处 for(int l=1;l<=5;l++){//表示m[i,j]中 j-i 的值 for(int i=1;i<=6-l;i++){//表示每一次要算的斜边数组 int j=i+l; m[i][j]=1000000000;//先置一个大数,要保证它比最复杂的矩阵乘法复杂度还大 for(int k=i;k<j;k++){//找到最小的m[i,j] int dex=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j]; if(dex<m[i][j]){ m[i][j]=dex; mark[i][j]=j;//记录切分处 } } } } System.out.println(m[1][6]); } }
精力所限,马上没有时间去实现凸多边形三角剖分跟最长公共子序列了,以后有时间会实现,我现在给一个链接,写得不错,可以作为参考。
相关文章推荐
- 【编程素质】算法-矩阵连乘问题(枚举法、备忘录法、动态规划)
- 动态规划 矩阵连乘问题
- 矩阵连乘 动态规划
- 动态规划之最优矩阵连乘
- 0010算法笔记——【动态规划】矩阵连乘问题
- 动态规划 矩阵连乘问题
- 动态规划求解矩阵连乘的最优时间复杂度
- 矩阵连乘最优解---动态规划
- 矩阵连乘 动态规划
- 动态规划之矩阵连乘问题
- 算法[动态规划]-矩阵连乘问题
- 动态规划之矩阵连乘最优化问题
- 矩阵连乘-动态规划
- C语言矩阵连乘 (动态规划)详解
- 矩阵连乘--动态规划
- 矩阵连乘 动态规划
- 动态规划——矩阵连乘的问题
- 矩阵连乘-动态规划-(只是感觉描述的清晰易懂,并不是什么新算法)
- 夕拾算法进阶篇:28)矩阵连乘(动态规划DP)
- 【动态规划】矩阵连乘问题