一、算法要求
给定n个矩阵{A,A,A,,…,An},其中,Ai和Ai+1( i=1,2,…,n-1)是可乘的。用加括号的方法表示矩阵连乘的次序,不同的计算次序计算量(乘法次数)是不同的,找出一种加括号的方法,使得矩阵连乘的计算量最小。
1. 思路
给定n个矩阵{A1,A2,…,An},其中A与Ai+1是可乘的(i=1,2,…,n-1)。考察这n个矩阵的连乘积A1A2…An。由于矩阵乘法满足结合律,因此计算矩阵的连乘积可以有不同的计算次序。
这种计算次序可以用加括号的方式来确定。若一个矩阵连乘积的计算次序完全确定,也就是说,该连乘积已完全加括号,则可依此次序反复调用两个矩阵相乘的标准算法计算出矩阵连乘积。
完全加括号的矩阵连乘积可递归地定义为:
①单个矩阵是完全加括号的;
②矩阵连乘积A是完全加括号的,则A可表示为两个完全加括号的矩阵连乘积B和C的乘积并加括号,即A=(BC)。
例如,矩阵连乘积A1A2A3A4可以有以下5种完全加括号方式:
(A1(A2(A3A4))),(A1((A2A3)A4)),((A1A2)(A3A4)),((A1(A2A3))A4),(((A1A2)A3)A4)
每种完全加括号方式对应一种矩阵连乘积的计算次序,而矩阵连乘积的计算次序与其计算量有密切关系。
首先考虑计算两个矩阵乘积所需的计算量。
计算两个矩阵乘积的标准算法如下,其中,ra、ca和rb、cb分别表示矩阵A和B的行数和列数。
2. 示例
二、完整代码
1. 主文件
main.cpp:
// Project1: 矩阵连乘法
#include<iostream>
using namespace std;
const int rangeMatrix = 100;
int p[rangeMatrix]; //行列数组
int m[rangeMatrix][rangeMatrix], //结果数组
s[rangeMatrix][rangeMatrix]; //断点数组
int n;
// n = 5
// p[] = {3 5 10 8 2 4}
void Print(int i, int j) {
if (i == j) {
cout << "A["
<< i << "]";
return;
}
cout << "(";
Print(i, s[i][j]);
Print(s[i][j] + 1, j);
cout << ")";
}
void MatrixChain() {
int i, j, r, k;
memset(m, 0, sizeof(m));
memset(s, 0, sizeof(s)); //初始化数组元素为0
for (r = 2; r <= n; r++) { //不同规模的子问题
for (i = 1; i <= n - r + 1; i++) {
j = i + r - 1;
m[i][j] = m[i + 1][j] + p[i - 1] * p[i] * p[j];//决策为k=i的乘法次数
s[i][j] = i; //子问题的最优策略是i
for (k = i + 1; k < j; k++) { //对从i到j的所有决策,求最优值,记录最优策略{
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;
}
}
}
}
}
int main() {
cout << "#Please enter the number of matrices (n): ";
cin >> n;
cout << "#Please enter the 'row' of the matrix "
<< "and the 'column' of the last matrix: ";
int i, j;
for (i = 0; i <= n; i++) {
cin >> p[i];
}
MatrixChain();
cout << "#Optimal matrix multiplication order is: ";
Print(1, n);
cout << "\n#The minimum calculation amount is:"
<< m[1][n] << endl;
return 0;
}
2. 效果展示
三、补充
MatrixChain的运行举例:
由m[1][6]=15125可知这6个矩阵连乘积的最小运算次数为15125。
由s[1][6] = 3 可知A[1: 6]的最优计算次序为A[1: 3] A[4: 6];
由s[1][3] = 1 可知A[1: 3]的最优计算次序为A[1: 1] A[2: 3];
由s[4][6] = 5 可知A[4: 6]的最优计算次序为A[4: 5] A[6: 6];
因此最优计算次序为:(A1(A2A3))((A4A5)A6)。
算法复杂度分析:
(1)时间复杂度:
由程序可以得出:语句t=m[i][k] + m[k+1][j]+p[i-1]*p[k]*p[j],它是算法的基本语句,在3层for循环中嵌套。最坏情况下,该语句的执行次数为O(n3),print()函数算法的时间主要取决于递归,时间复杂度为O(n)。故该程序的时间复杂度为O(n3)。
(2)空间复杂度:
该程序的输入数据的数组为p[],辅助变量为i、j、r、t、k、m[]I]、s[][],空间复杂度取决于辅助空间,因此空间复杂度为O(n2)。
文档供本人学习笔记使用,仅供参考。