给定一个有n个矩阵的矩阵链A1A2A3…An,其中矩阵Ai(i=1,2,3…n)的维度为pi-1*pi。我们知道,两个维度分别为m*r和r*n的矩阵用一般的矩阵乘法相乘,所需的运算次数为m*r*n,最后得到一个维度为m*n的结果矩阵。对于矩阵链问题,因为矩阵乘法具有结合律,其运算顺序有很多中选择。换句话说,不论如何括号其乘积,最后结果都会是一样的。例如,若有四个矩阵A、B、C和D,将可以有:
(ABC)D = (AB)(CD) = A(BCD) = A(BC)D = ...
但括号其乘积的顺序会影响到需要计算乘积所需简单算术运算的数目,即其效率。例如,设A为一10*30矩阵,B为30*5矩阵与C为5*60矩阵,则:
(AB)C有(10*30*5) + (10*5*60) = 1500 + 3000 = 4500 个运算 A(BC)有(30*5*60) + (10*30*60) = 9000 + 18000 = 27000 个运算 ...
明显地,第一种方式要有效多了。所以,矩阵链乘法问题也就是如何对矩阵乘积加括号,使得它们的乘法次数达到最少。
输入的第二行包含n+1个整数,分别表示pi(0<=i<=n),其中每个pi在[1,200]范围内。Output输出一个整数表示最少要进行的乘法次数。
#include <iostream>
#include <cstring>
using namespace std;
int n,p[1001];
int d[1001][1001];
//d(i,j)=min(d(i,k)+d(k+1,j))+p[i]*p[j+1]*p[k+1];d(i,j)表示第i到第j个矩阵链乘的最小次数,边界是i=j+1或i=j
int dp(int x,int y)
{
int &ans=d[x][y];
if(ans)
return ans;
if(y==1+x)
return p[x]*p[y+1]*p[y];
if(y==x)
return 0;
ans=100000;
for(int i=x+1;i<y;i++)
{
ans=min(ans,dp(x,i)+dp(i+1,y)+p[x]*p[y+1]*p[i+1]);
}
return ans;
}
int main()
{
while(cin>>n)
{
memset(d,0,sizeof(d));
for(int i=1;i<=n+1;i++)
cin>>p[i];
int ans=dp(1,n);
cout<<ans<<endl;
}
return 0;
}
Sample Input
3 1 2 3 4 3 10 30 5 60
Sample Output
18 4500