Description
给定n个矩阵{A0,A1,…,An-1}, 其中Ai,i=0,…,n-1的维数为pi*pi+1,并且Ai与Ai+1是可乘的。考察这n个矩阵的连乘积A0A1…An-1,由于矩阵乘法满足结合律,所以计算矩阵的连乘可有许多不同的计算次序。矩阵连乘问题是确定计算矩阵连乘积的计算次序,使得按照这一次序计算矩阵连乘积,需要的“数乘”次数最少。Input第一行输入n的值,第二行输入n个矩阵的维数pi(i=0,…,n)。Output最少乘法次数。Sample Input
630 35 15 5 10 20 25
Sample Output
15125
Source
矩阵连乘算法算是经典的动态规划算法的问题(Dynamic Programming)(明显的具有最优子结构和重叠子问题的特点,证明略)。既然是动态规划问题,那很明显是用到了数组来存储子结构的解。
我们这里主要用到两个数组,一个是p数组,这是一维数组,存储着矩阵的维数,因为相邻两边的矩阵维数默认相同,对于n个矩阵来说,只需n+1个空间即可存储。
还有一个是m数组,这是一个二维数组m,m[i][j]是表示第i个矩阵和第j个矩阵相乘的计算次数。那么m[i][i]理所当然就是0啦,因为是自己乘自己。
如果i不等于j的话,我们就来一个递归的操作:设一个中间值k,i<=k<j,则m[i][j]=min{m[i][k]+m[k+1][j]+p[i]*p[k+1]*p[j+1]}(因为这个值是不停地比较产生的,所以需要去所有情况的最小值)这样就形成了一个类似于上三角的矩阵来表示递推计算次序:
右上角的是最终我们需要求的值,即是m[0][n-1],代码实现如下:
#include <iostream>
using namespace std;
void Mchain(int *p,int m[][100],int n)//计算将m矩阵数字填满
{
for(int r=2;r<=n;r++)
{
for(int i=0;i<=n-r;i++)
{
int j=i+r-1;
m[i][j]=m[i][i]+m[i+1][j]+p[i]*p[i+1]*p[j+1];
for(int k=i+1;k<j;k++)
{
int t=m[i][k]+m[k+1][j]+p[i]*p[k+1]*p[j+1];
if(t<m[i][j])
{
m[i][j]=t;
}
}
}
}
}
int main()
{
int n;
int p[100],m[100][100];
cin>>n;
for(int i=0;i<=n;i++)
{
cin>>p[i];
}
for(int i=0;i<n;i++)
{
m[i][i]=0;//矩阵自身相乘计算次数为0
}
Mchain(p,m,n);
cout<<m[0][n-1]<<endl;
return 0;
}