【DP】矩阵链乘法

来源:互联网 发布:全息瞄准镜 知乎 编辑:程序博客网 时间:2024/04/29 21:17
问题描述:给定n个矩阵{A1,A2,…,An},其中Ai与Ai+1是可乘的,i=1,2 ,…,n-1。如何确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。


实例:假设现在6个矩阵,大小分别是:30*35;35*15;15*5;5*10;10*20;20*25,计算出的矩阵最少连乘积次数,输出最优结构。

为了实现起来简单,我在java里面主要用静态方法(调用起来方便),在这里主要分析算法。

主要分析过程参考<算法导论>

分析: 矩阵链乘法问题描述: 给定由n个矩阵构成的序列[A1,A2,...,An],对乘积A1A2...An,找到最小化乘法次数的加括号方法。 1)寻找最优子结构此问题最难的地方在于找到最优子结构。对乘积A1A2...An的任意加括号方法都会将序列在某个地方分成两部分,也就是最后一次乘法计算的地方,我们将这个位置记为k,也就是说首先计算A1...Ak和Ak+1...An,然后再将这两部分的结果相乘。最优子结构如下:假设A1A2...An的一个最优加括号把乘积在Ak和Ak+1间分开,则前缀子链A1...Ak的加括号方式必定为A1...Ak的一个最优加括号,后缀子链同理。一开始并不知道k的确切位置,需要遍历所有位置以保证找到合适的k来分割乘积。 2)构造递归解设m[i,j]为矩阵链Ai...Aj的最优解的代价,则          |- 0    如果i = jm[i,j] =  |          | -min(i≤k<j) {m[i,k] + m[k+1,j] + Ai.row*Ak.col*Aj.col}  如果i < j  3)构建辅助表,解决重叠子问题从第二步的递归式可以发现解的过程中会有很多重叠子问题,可以用一个nXn维的辅助表t[n][n]来保存子问题的解,表中每个元素包含2个信息,分别是最优乘积代价及其分割位置k 。辅助表t[n][n]可以由2种方法构造,一种是自底向上填表构建,该方法要求按照递增的方式逐步填写子问题的解,也就是先计算长度为2的所有矩阵链的解,然后计算长度3的矩阵链,直到长度n;另一种是自顶向下填表的备忘录法,该方法将表的每个元素初始化为某特殊值(本问题中可以将最优乘积代价设置为一极大值),以表示待计算,在递归的过程中逐个填入遇到的子问题的解。备忘录法会比自底向上法慢一个常数因子,因为前者有递归调用的代价,维护表格的开销也稍大。



package 矩阵链乘法;public class Matrix {public static final int n = 6;//6个矩阵,分别是30*35;35*15;15*5;5*10;10*20;20*25public static int[] p = {30,35,15,5,10,20,25};//记录a、b之间的最优链乘的积public static int[][] matrix = new int[n][n];//记录a、b之间的最优分割点public static int[][] s = new int[n][n];public static void init(){for(int i=0;i<6;i++)matrix[i][i]=0;for(int m=0;m<n;m++)for(int j=0;j<n;j++)s[m][j]=-1;}public static void Matrix_Chain_Order(){//自底向上进行计算for(int i=1;i<n;i++){//这里计算b-a = j时,最优链乘的积;  因为要进行计算,说明a、b至少差1,否则他的值为0;最多相差n-1;for(int j=0;j<n-i;j++){  //1.这里j+i 必须要小于n,否则会导致越界; System.out.println("current is matrix["+j+"]"+"["+(i+j)+"]");matrix[j][j+i]=1111111111;    //这里要开始计算最优划分点,由于需要独立计算,而且因为是由底向上的,所以matrix[a][b]中,b-a<i的值都有记录;这里设置的初值为一个很大的数值。int q =0;for(int k=j+1;k<=j+i;k++){q =matrix[j][k-1]+matrix[k][i+j]+p[j]*p[k]*p[i+j+1];if(q<matrix[j][j+i]){matrix[j][i+j]=q;s[j][i+j]=k;}}System.out.println("    s["+j+"]"+"["+(i+j)+"]"+"="+matrix[j][i+j]+" 分割点是:(-1代表没有分割点)"+s[i][j+i]);}}}public static void shows(int start,int end){if(start==end){System.out.print(end);return;}else{System.out.print("(");shows(start,s[start][end]-1);shows(s[start][end],end);System.out.print(")");}}public static void main(String[] args) {init();Matrix_Chain_Order();System.out.println(matrix[1][4]);System.out.println(s[0][5]);//这里输出六个矩阵的具体乘法shows(0,5);}}


0 0