- 本文作者: lemon
- 本文链接: https://lemon2013.github.io/2017/07/13/dynamic-matrix-chain/
- 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!
矩阵链乘法
问题描述
给定一个 nn 个矩阵的序列(矩阵链) <A1,A2,…,AnA1,A2,…,An>,我们希望计算它们的乘积
A1A2…AnA1A2…An
为了计算表达式,我们可以先用括号明确计算次序,然后利用标准的矩阵相乘算法进行计算。由于矩阵乘法满足结合律,因此任何加括号的方法都会得到相同的计算结果。我们称有如下性质的矩阵乘积链为完全括号话:它是单一矩阵,或者是两个完全括号化的矩阵乘积链的积,且已外加括号。例如,如果矩阵链为<A1,A2,A3,A4A1,A2,A3,A4>,则共有 5 种完全括号化的矩阵乘积链:
(A1(A2(A3A4))),(A1(A2A3(A4))),((A1A2)(A3A4)),((A1A2A3)(A4)),(((A1A2)A3)A4)(A1(A2(A3A4))),(A1(A2A3(A4))),((A1A2)(A3A4)),((A1A2A3)(A4)),(((A1A2)A3)A4)
两个矩阵 AA 和 BB 只有相容,即AA的列数等于 BB 的行数时,才能相乘。如果 AA 是 p×qp×q 的矩阵,BB 是 q×rq×r 的矩阵那么乘积 CC 是 p×rp×r 的矩阵。计算 CC 的代价为 pqrpqr,我们使用标量乘法的次数来表示计算代价。
矩阵链乘法问题:给定 nn 个矩阵的链<A1,A2,…,AnA1,A2,…,An>,矩阵 AiAi 的规模为 pi−1×pi(1≤i≤n)pi−1×pi(1≤i≤n),求完全括号化方案,使得计算乘积 A1A2…AnA1A2…An所需的标量乘法次数最少。
动态规划求解
最优解结构
为了方便起见,我们用符号 Ai.j(i≤j)Ai.j(i≤j) 表示AiAi+1…AjAiAi+1…Aj 乘积的结果矩阵。
假设AiAi+1…AjAiAi+1…Aj 的最优括号化方案的分割点在 AkAk 和 Ak+1Ak+1 之间。那么,继续对”前缀”子链 AiAi+1…AkAiAi+1…Ak,”后缀” Ak+1Ak+2…AjAk+1Ak+2…Aj 进行括号化 (独立求解)。
递归定义
令 m[i,j]m[i,j] 表示计算矩阵 Ai.jAi.j 所需标量乘法次数的最小值,原问题的最优解—–计算A1..nA1..n 所需的最低代价就是 m[1,n]m[1,n]。
我们假设 AiAi+1…AjAiAi+1…Aj 的最优括号化方案的分割点在矩阵 AkAk 和 Ak+1Ak+1 之间,其中 i≤k<ji≤k<j。 那么,m[i,j]m[i,j] 就等于计算 Ai.kAi.k 和 Ak+1.jAk+1.j 的代价加上两者相乘的代价的最小值:
m[i,j]=m[i,k]+m[k+1,j]+pi−1pkpjm[i,j]=m[i,k]+m[k+1,j]+pi−1pkpj
因此递归求解公式为
if i==j
m[i,j]=0m[i,j]=0
else if i<j
m[i,j]=min{m[i,k]+m[k+1,j]+pi−1pkpj},i≤k<jm[i,j]=min{m[i,k]+m[k+1,j]+pi−1pkpj},i≤k<j
计算最优值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public static void getMatrixChanOrder(int[] p) { int n = p.length; long[][] dp = new long[n][n]; int[][] s = new int[n][n]; for (int i = 0; i < n; i++) { dp[i][i] = 0; } for (int l = 2; l < n; l++) { for (int i = 1; i <= n - l; i++) { int j = i + l - 1; dp[i][j] = Long.MAX_VALUE; for (int k = i; k < j; k++) { long temp = dp[i][j]; dp[i][j] = Math.min(dp[i][j], dp[i][k] + dp[k + 1][j] + p[i - 1] * p[k] * p[j]); if(temp!=dp[i][j]){ s[i][j]=k; } } } } System.out.println(dp[1][n-1]+" "+s[1][n-1]); } |
假定矩阵 AiAi 的规模为 pi−1×pi,(i=1,2,…,n)pi−1×pi,(i=1,2,…,n),输入的序列 p=p=<p0,p1,…,pnp0,p1,…,pn>
比如:
矩阵 | A1A1 | A2A2 | A3A3 | A4A4 | A5A5 | A6A6 |
---|---|---|---|---|---|---|
规模 | 30×3530×35 | 35×1535×15 | 15×515×5 | 5×105×10 | 10×2010×20 | 20×2520×25 |
则
1 | int[] p = { 30, 35, 15, 5, 10, 20, 25 }; |
构造最优解
1 2 3 4 5 6 7 8 9 10 | public static void printOptimal(int[][] s,int i,int j){ if(i==j){ System.out.print("A"+i); }else{ System.out.print("("); printOptimal(s,i,s[i][j]); printOptimal(s,s[i][j]+1,j); System.out.print(")"); } } |
完整代码以及相应示例图见 https://github.com/lemon2013/algorithm/blob/master/MatrixChain.java