多个矩阵连乘,给这样的矩阵序列加括号,使乘法的计算次数最小。使用的是动态规划的思想。
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
void MatrixChain(int n, int *p, int **m, int **s){
/*
找到矩阵链乘法需要的最小乘法次数,以及划分的方式
:param n: 矩阵A的个数
:param p: 存放矩阵维度的数组,有n+1个元素
:param m: m[i, j]存放矩阵i到矩阵j
这个矩阵序列在最优划分下的乘法次数
:param s: s[i, j]存放矩阵i到矩阵j
这个矩阵序列在最优划分下时,断开的位置k
在位置k断开,代表的是将A_k和A_(k+1)分开
m, s下标从1开始
m[i][j] = 0, i=j
m[i][j] = min{m[i][k], m[k+1][j]+p[i-1]*p[k]p[j]} for k /in [i,j), i<j
*/
for(int i = 1; i <= n; ++i) m[i][i] = 0;
for(int r = 1; r < n; ++r){ // r是间隔,计算m[i][i+r]
for(int i = 1; i <= n-r; ++i){
int j = i+r;
m[i][j] = m[i+1][j]+p[i-1]*p[i]*p[j]; // 把i, i+1之间断开
s[i][j] = i;
for(int k = i+1; k < j; ++k){ // 划分点从k枚举到j-1
int tmp = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];
if(tmp < m[i][j]) {
m[i][j] = tmp;
s[i][j] = k;
}
}
}
}
}
string int2str(int n){
stringstream ss;
ss << n;
string res;
ss >> res;
return res;
}
string Traceback(int i, int j, int **s){
if(i == j) return "A"+int2str(i);
string left = Traceback(i, s[i][j], s);
string right = Traceback(s[i][j]+1, j, s);
return '('+left+right+')';
}
int main(){
const int n = 6;
int *p = new int[n+1];
p[0]=30;p[1]=35;p[2]=15;p[3]=5;p[4]=10;p[5]=20;p[6]=25;
int **m = new int*[n+1], **s = new int*[n+1];
for (int i = 0; i <= n; ++i){
m[i] = new int[n+1](); // 每个元素初始化为0
s[i] = new int[n+1]();
}
MatrixChain(n, p, m, s);
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= n; ++j){
cout << m[i][j] << ' ';
} cout << endl;
}
cout << "The minimal number of multiply is : " << m[1][n] << endl;
cout << "The order of multiply is :" << Traceback(1, n, s) << endl;
return 0;
}