问题描述:
给定n个矩阵:A1, A2, ... , An,其中Ai与Ai+1是可乘的,i = 1,2 ...,n-1。确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。输入数据为矩阵个数和每个矩阵规模,输出结果为计算矩阵连乘积的计算次序和最少数乘次数。
递推关系:
m[i][j] = 0, i = j;
= m[i][k] + m[k][j] + p[i - 1] * p[k] * p[j]; i != j;
代码:
//测试样例
/*
输入
6
30 35 15 5 10 20 25
输出
((A1(A2A3))((A4A5)A6))
15125
*/
#include <bits/stdc++.h>
using namespace std;
int p[1010];
int m[1010][1010];
int s[1010][1010];
int n;
void Traceback(int i, int j)
{
if(i == j)
{
cout << "A" << i;
return;
}
else
{
cout << "(";
Traceback(i, s[i][j]);
Traceback(s[i][j] + 1, j);
cout << ")";
}
}
void MatrixChain()
{
for(int i = 1; i <= n; ++i)
m[i][i] = 0;
for(int r = 2; r <= n; ++r)//注释1见下
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(m[i][j] > t)
{
m[i][j] = t;
s[i][j] = k;
}
}
}
}
void Input()
{
scanf("%d", &n);
//矩阵的行数和列数
for(int i = 0; i <= n; ++i)
scanf("%d", &p[i]);
}
int main()
{
Input();
MatrixChain();
Traceback(1, n);
cout << endl;
cout << m[1][n];
}
注释1:
很多同学(包括刚开始的我...)不理解第一个循环r,然后百度百度百度,终于找到了能理解的一篇博地址矩阵连乘详解。
具体的来说,动态规划是由低往上的,r 就表示一次连乘矩阵的个数,即:由两个矩阵的连乘逐渐到n个矩阵相乘。
另外改写了Traceback函数,使输出更易懂。