问题描述
给定n个矩阵{A1,A2,…,An},其中Ai与Ai+1是可乘的,i = 1,2,
…n-1。考虑这n个矩阵的乘积。由于竞争乘法满足结合律,故计算矩阵的连乘有许多不同的计算次序。这种计算次序可以用加括号的方式确定。若一个矩阵连乘的计算次序完全确定,这是就说该连乘已完全加括号。
例如,矩阵连乘A1 A2 *A3 *A4 可以有5种完全加括号的方式:(A1 (A2 (A3 *A4 ))), (A1 ((A2
A3) *A4)),((A1 *A2 )(A3 *A4)),(((A1 *A2 )*A3
)*A4)。每种加括号的方式确定了一个计算的次序。不同的计算次序与矩阵连乘的计算量有密切的关系。关于矩阵如何相乘这里我就不赘述了考虑3个矩阵{A1,A2,A3}连乘的例子,假设这3个矩阵的维数分别为 10×100, 100×5,
5×50。若按照((A1*A2)*A3)计算,则计算次数为10×100×5 + 10×5×50 = 7500若按(A1*(A2*A3))计算,则计算次数为 100×5×50 + 10×100×50 =
75000。第1种方法的计算次数是后者的10倍!由此可以看出,不同的加括号方式确定不同的计算次序对
矩阵乘法的运算量影响是巨大的。
矩阵连乘为题定义如下:给定n个矩阵{A1,A2,…,An},矩阵A1的维数为pi-1×pi, i = 1,2, …, n,如何给矩阵连乘A1*A2*….*An完全加上括号使用矩阵乘法中计算次数最少。
问题分析
若用穷举法,能够证明需要指数时间来求解。但是时间代价高昂。现在考虑用动态规划来求解连乘问题。
为方便起见用Ai…j表示矩阵乘法Ai*Ai+1*….Aj的结果。其中i < j。那么Ai*Ai+1*…..Aj一定在Ak与Ak+1之间被分裂。i<= k < j。问题Ai*Ai+1 … Aj完全加括号的开销等于计算矩阵 Ai…k 与计算 Ak+1…j的开销,再加上他们的结果相乘的开销。问题的最优子结构可以描述如下:假定问题Ai*Ai+1*…Aj被完全加括号的最优方式是在Ak与Ak+1之间被分裂,那么分裂 之后,最优解Ai*Ai+1*….Aj中的子链Ai*Ai+1….Ak一定是问题Ai*Ai+1*…Ak的最优加括号方式。同样,最优解Ak+1*Ak+2…Aj的子链一定是问题Ak+1*Ak+2*…Aj最优加括号方式。
根据上面分析,设m[i,j]表示计算Ai…j所需的最小计算次数 m[i,j] = min{m[i,k]+m[k+1,j]+pi-1pKpj }
其中pi-1和pi分别表示第i个矩阵的行和列
代码c++实现
#include<iostream>
void main()
{
int m[8][8], min;
int r[8] = {10, 20, 50, 1, 100, 4, 20, 2}; /* 矩阵维数 */
/* 初始化 */
memset(m,0,sizeof(m));
/* 每此增量加一 */
for (int l = 1; l < 7; l++)
{
/* 对于差值为 l 的两个元素 */
for (int i = 1; i <= 7 - l; i++)
{
j = i + l;
/* 求其最小组合方式 */
min = m[i][i] + m[i+1][j] + r[i-1] * r[i] * r[j];
middle[i][j] = i;
for (int k = i + 1; k < j; k++)
{
if (min > m[i][k] + m[k+1][j] + r[i-1] * r[k] * r[j])
{
min = m[i][k] + m[k+1][j] + r[i-1] *r[k]* r[j];
middle[i][j] = k;
}
}
m[i][j] = min;
}
}
std::cout<<m[1][N];
}
由以上代码可以很容易看出算法的时间复杂度为O(n^3)。即便如此也比穷举法的指数级时间复杂度快。
java实现
public class Matrix{
//计算最优值
public void matrixChain(int[]p, int[][]m, int [][]s)
{
int n=p.length-1;
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] = 999999999;
s[i][j] = i;
for (int k = i; 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 void TraceBack(int [][]s, int i, int j)
{
if(i!=j){
TraceBack(s,i,s[i][j]);
TraceBack(s,s[i][j]+1,j);
System.out.println("Multiply A["+i+":"+s[i][j]+"] and A["+(s[i][j]+1)+":"+j+"]");
}
}
// 打印加括号的最优解方案
public void OptimalParens(int[][] s,int i,int j){
if(i==j)System.out.print("(A"+i);
else{
OptimalParens(s,i,s[i][j]);
OptimalParens(s,s[i][j]+1,j);
System.out.print(")");
}
}
}
测试类
//矩阵阶乘的测试
public class MatrixText {
public static void main(String agrs[])
{
int[] p={30,35,15,5,10,80,25,65,40,20};
int n=p.length;
int [][]m=new int [n][n];
int [][]s=new int [n][n];
Matrix m1=new Matrix();
m1.matrixChain(p, m, s);
System.out.println("该矩阵阶乘子问题数乘的次数:");
for(int i=1;i<m.length;i++){
for(int j=1;j<m.length;j++){
if(i>j)
{
System.out.print("----"+"\t");
}
else
{
System.out.print(m[i][j]+"\t");
}
}
System.out.println();
}
System.out.println();
System.out.println("该矩阵阶乘子问题数乘的次数:");
for(int i=1;i<s.length;i++){
for(int j=1;j<s.length;j++){
if(i>j)
{
System.out.print("----"+"\t");
}
else
{
System.out.print(s[i][j]+"\t");
}
}
System.out.println();
}
System.out.println();
System.out.println("该矩阵阶乘的最优解:");
m1.TraceBack(s,1,n-1);
m1.OptimalParens(s,1,n-1);
}
}
运行结果
该矩阵阶乘子问题数乘的次数:
0 15750 7875 9375 23875 25625 39750 49000 50000
—- 0 2625 4375 20625 21000 36125 44750 45250
—- —- 0 750 10000 15875 27000 38125 40625
—- —- —- 0 4000 14000 22125 35125 39125
—- —- —- —- 0 20000 36250 62250 70250
—- —- —- —- —- 0 130000 145000 124500
—- —- —- —- —- —- 0 65000 84500
—- —- —- —- —- —- —- 0 52000
—- —- —- —- —- —- —- —- 0
该矩阵阶乘子问题数乘的次数:
0 1 1 3 3 3 3 3 3
—- 0 2 3 3 3 3 3 3
—- —- 0 3 3 3 3 3 3
—- —- —- 0 4 5 6 7 8
—- —- —- —- 0 5 6 7 8
—- —- —- —- —- 0 6 6 6
—- —- —- —- —- —- 0 7 7
—- —- —- —- —- —- —- 0 8
—- —- —- —- —- —- —- —- 0
该矩阵阶乘的最优解:
Multiply A[2:2] and A[3:3]
Multiply A[1:1] and A[2:3]
Multiply A[4:4] and A[5:5]
Multiply A[4:5] and A[6:6]
Multiply A[4:6] and A[7:7]
Multiply A[4:7] and A[8:8]
Multiply A[4:8] and A[9:9]
Multiply A[1:3] and A[4:9]
(A1(A2(A3))(A4(A5)(A6)(A7)(A8)(A9))
Process finished with exit code 0