题目描述
给定n个矩阵{A1,A2,…,An},其中Ai与Ai+1是可乘的,i=1,2…,n-1。如何确定计算矩阵连乘积的计算次序,使得依此次序 计算矩阵连乘积需要的数乘次数最少。
样例输入
1
5 10 4 6 10 2
样例输出
348
(A1(A2(A3(A4A5))))
思路
例如:
A1是5 * 10 的矩阵
A2是10 * 100的矩阵
A3是100 * 2的矩阵
那么有两种加括号的方法:
1、 (A1A2)A3
2、 A1(A2A3)
第一种方法的计算量:510100+51002=6000;
第二种方法的计算量:101002+5102=2100;
可以看出不同计算次序计算量也不同。
设计算A[i:j],1≤i≤j≤n,所需要的最少数乘次数m[i,j],则原问题的最优值为m[1,n]。
当i=j时,A[i:j]=Ai,因此,m[i][i]=0,i=1,2,…,n
当i<j时,若A[i:j]的最优次序在Ak和Ak+1之间断开,i<=k<j,则:m[i][j]=m[i][k]+m[k+1][j]+pi-1pkpj。由于在计算是并不知道断开点k的位置,所以k还未定。不过k的位置只有j-i个可能。因此,k是这j-i个位置使计算量达到最小的那个位置。
综上:
状态转移方程:
m[i][j] = 0 if i = j
m[i][j]=min{m[i][k]+m[k+1][j]+p[i-1]p[k]p[j]} if i < j
代码
#include<iostream>
using namespace std;
const int N = 1e2+10;
int f[N][N];
int s[N][N];
int n, m;
int p[N];
void solution(int l,int r)
{
if(l == r)
{
cout<<"A"<<l;
return ;
}
cout<<"(";
solution(l,s[l][r]);
solution(s[l][r]+1,r);
cout<<")";
}
int main()
{
cin >> m;
int n = m - 1;
for(int i = 0; i <= n; i++)
{
cin>>p[i];
}
for(int len = 2; len <= n; len++)
{
for(int i = 1; i <= n - len +1; i++)
{
int j = i + len -1;
f[i][j] = f[i+1][j] + p[i-1]*p[i]*p[j];
s[i][j] = i;
for(int k = i + 1; k < j; k++)
{
int temp = f[i][k] + f[k+1][j] + p[i-1] * p[k] * p[j];
if(temp < f[i][j])
{
f[i][j] = temp;
s[i][j] = k;
}
}
}
}
cout<<f[1][n]<<endl;
solution(1,n);
return 0;
}