动态规划-矩阵连乘问题

来源:互联网 发布:鲁迅文学院网络班 编辑:程序博客网 时间:2024/06/01 08:52

参考
1.小白建议看这一篇文章搞懂相关概念先:矩阵连乘详解一滴新浪博客
2.大神还可以直接看代码版的:第3章 动态规划 矩阵连乘问题 - Vector - 博客频道 - CSDN.NET
3.算法笔记——【动态规划】矩阵连乘问题 - Michael的博客 - 博客频道 - CSDN.NET

数学知识

既然这篇文章叫做矩阵连乘详解,那么我就不能辜负详解这两个字,只有把一个原来不懂的的人弄懂了,才叫详解。

言归正传,首先让我们复习一下矩阵连乘的有关知识。对于矩阵知识很了解的人可以跳过矩阵知识这块内容,不过笔者建议最好复习一下。

矩阵知识:

这里写图片描述

矩阵乘法:

矩阵相乘只有在第一个矩阵的列数和第二个矩阵的行数相同時才有定义。假如A为m×n矩阵,B为n×p矩阵,则他們的乘AB(有时记做A·B)会是一个m×p矩阵。
例如一个2x3的矩阵与一个3x2的矩阵的乘会是一个2x2的矩阵 。

这里写图片描述

矩阵连乘:

设有矩阵M1,M2,M3,M4,
其维数分别是10×20, 20×50, 50×1 和1×100,现要求出这4个矩阵相乘的结果。我们知道,若矩阵A的维数是p×q,矩阵B的维数是q×r,则A与B相乘后所得矩阵AB的维数是p×r。按照矩阵相乘的定义,求出矩阵AB中的一个元素需要做q次乘法(及q-1次加法)。这样,要计算出AB就需要做p×q×r次乘法。为简单起见,且由于加法比同样数量的乘法所用时间要少得多,故这里我们暂不考虑加法的计算量。由于矩阵连乘满足结合律,故计算矩阵连乘的方式可以有多种。

例如,我们可以按M1(M2(M3M4))的方式去计算,
也可以按(M1(M2M3))M4的方式去计算,所得结果是相同的。
但是值得注意的是,
按前一方式计算需要做125,000次乘法,
而按后一方式计算只需要做2,200次乘法。
由此可见,矩阵连乘的运算次序对于所需要的计算量
(所需乘法次数)有着极大的影响。
M3M4:50*1*100=5,000;M2(M3M4):20*50*100=100,000
M1(M2(M3M4)):10*20*100=20,000
(M2M3):20*50*1=1000;(M1(M2M3)):10*20*1=200 ;
(M1(M2M3))M4:10*1*100=1000

所以问题是:如何确定运算顺序,可以使计算量达到最小化。

算法思路:

例:设要计算矩阵连乘乘积A1A2A3A4A5A6,其中各矩阵的维数分别是:
A1:30*35; A2:35*15; A3:15*5; A4:5*10; A5:10*20; A6:20*25

递推关系:

 设计算A[i:j],1≤i≤j≤n,所需要的最少数乘次数m[i,j],则原问题的最优值为m[1,n]。  当i=j时,A[i:j]=Ai,因此,m[i][i]=0,i=1,2,…,n  当i<j时,若A[i:j]的最优次序在Ak和Ak+1之间断开,i<=k<j,则:m[i][j]=m[i][k]+m[k+1][j]+pi-1pkpj。由于在计算是并不知道断开点k的位置,所以k还未定。不过k的位置只有j-i个可能。因此,k是这j-i个位置使计算量达到最小的那个位置。  综上,有递推关系如下

这里写图片描述

构造最优解:

若将对应m[i][j]的断开位置k记为s[i][j],在计算出最优值m[i][j]后,可递归地由s[i][j]构造出相应的最优解。s[i][j]中的数表明,计算矩阵链A[i:j]的最佳方式应在矩阵Ak和Ak+1之间断开,即最优的加括号方式应为(A[i:k])(A[k+1:j)。因此,从s[1][n]记录的信息可知计算A[1:n]的最优加括号方式为(A[1:s[1][n]])(A[s[1][n]+1:n]),进一步递推,A[1:s[1][n]]的最优加括号方式为(A[1:s[1][s[1][n]]])(A[s[1][s[1][n]]+1:s[1][s[1][n]]])。同理可以确定A[s[1][n]+1:n]的最优加括号方式在s[s[1][n]+1][n]处断开…照此递推下去,最终可以确定A[1:n]的最优完全加括号方式,及构造出问题的一个最优解。

package Matrix;  /**  * Created by Administrator on 2016/1/20.  */  public class Matrix {      public static void MatrixChain(int[] p,int n, int[][] m, int[][] s) {       for (int i = 1; i <= n; i++) {           m[i][i] = 0;       }          for(int r = 2;r <= n; r++ ) {              for(int i = 1; i <= n-r+1; i++) {                  int j = i+r-1;                  m[i][j] = m[i+1][j] + p[i-1]*p[i]*p[j];                  s[i][j] = i;                  for(int k = i+1; k < j; k++) {                      int t = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];                      if(t < m[i][j]) {                          m[i][j] = t;                          s[i][j] = k;                      }                  }              }          }      }      public static void Traceback(int i, int j, int[][] s) {          if(i == j) return;          Traceback(i,s[i][j],s);          Traceback(s[i][j] + 1,j,s);          System.out.println("Multiply    A" + i + "," + s[i][j] + "and A" + (s[i][j] + 1) + "," + j);      }      public static void main(String[] args) {          Matrix mc = new Matrix();          int n = 7;          int p[] = { 30, 35, 15, 5, 10, 20, 25 };          int m[][] = new int[n][n];          int s[][] = new int[n][n];          int l = p.length-1;          mc.MatrixChain(p, l,m, s);          for (int i = 1; i < n; i++) {              for (int j = 1; j < n; j++) {                  System.out.print(m[i][j] + "\t");              }              System.out.println();          }          System.out.println();          for (int i = 1; i < n; i++) {              for (int j = 1; j < n; j++) {                  System.out.print(s[i][j]+" ");              }              System.out.println();          }          mc.Traceback( 1, 6, s);      }  }

这里写图片描述


如果对你有帮助,可以点击“点赞”哦`(*∩_∩*)′




本文转载于:
1.算法笔记——【动态规划】矩阵连乘问题 - Michael的博客 - 博客频道 - CSDN.NET
2.矩阵连乘详解一滴新浪博客