您的位置:首页 > 编程语言 > Java开发

动态规划(dynamic programming)及示例(矩阵连乘、最长公共子序列、三角剖分)

2017-02-25 13:33 225 查看
动态规划是一个比较重要的算法思想,只要学了算法相关课程,一定会有这一章节。我会介绍动态规划的主要思想,也会在后面用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]);
}
}


精力所限,马上没有时间去实现凸多边形三角剖分跟最长公共子序列了,以后有时间会实现,我现在给一个链接,写得不错,可以作为参考。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息