题目:
计算矩阵连乘积A1,A2,...,An,其中Ai的维度为p[i-1]*p[i]。输入规模n,p[0]~p[n],输出最少乘的次数和断点处也就是乘法顺序。
思路:
区间dp,m[i][j]表示从Ai到Aj区间内的最少乘的次数,枚举k(i<k<j),状态转移方程m[i][j]=max(m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j])。
用s[i][j]记录每次最少次数的时候是在哪个地方断开,即k的位置。详见代码。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=101;
int m[maxn][maxn],s[maxn][maxn],p[maxn];
int n;
void MatrixChain()
{
for(int i=1; i<=n; i++)
m[i][i]=0;
for(int len=2; len<=n; len++)
{
for(int i=1; i<=n-len+1; i++)
{
int j=i+len-1;
m[i][j]=m[i][i]+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(t<m[i][j])
{
m[i][j]=t;
s[i][j]=k;
}
}
}
}
}
void Traceback(int i,int j)
{
if(i==j) return;
Traceback(i,s[i][j]);
Traceback(s[i][j]+1,j);
printf("Multiply A%d,%d and A%d,%d\n",i,s[i][j],s[i][j]+1,j);
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=0;i<=n;i++)
scanf("%d",&p[i]);
MatrixChain();
printf("%d\n",m[1][n]);
Traceback(1,n);
}
return 0;
}
6
30 35 15 5 10 20 25
8
30 35 15 5 10 20 25 10 30
output
15125
Multiply A2,2 and A3,3
Multiply A1,1 and A2,3
Multiply A4,4 and A5,5
Multiply A4,5 and A6,6
Multiply A1,3 and A4,6
18625
Multiply A2,2 and A3,3
Multiply A1,1 and A2,3
Multiply A4,4 and A5,5
Multiply A4,5 and A6,6
Multiply A4,6 and A7,7
Multiply A4,7 and A8,8
Multiply A1,3 and A4,8