矩阵最优连乘问题

问题 E: 矩阵最优连乘问题

时间限制: 1 Sec  内存限制: 128 MB
提交: 473  解决: 118
[提交][状态][社区]

题目描述

已知一组连乘矩阵的各维长度,要求计算并输出计算量最小的计算顺序表达式。

输入

每行为一组连乘矩阵的各维长度,行中第一个数字是连乘矩阵的个数n,n≤100,后面是n+1个维长。 矩阵个数为0表示输入结束。

输出

对每行输入,计算最优计算顺序,并以括号形式将计算表达式输出,各矩阵用A0, A1, ..的形式表示。

样例输入

1 10 202 10 20 303 10 20 30 406 30 35 15 5 10 20 250

样例输出

A0A0A1(A0A1)A2(A0(A1A2))((A3A4)A5)
动态规划经典问题。由于矩阵的乘法满足结合律,故计算矩阵的连乘积可以有不同的计算次序。
矩阵A和B可乘的条件是矩阵A的列数等于矩阵B的行数。若A是一个p*q的矩阵,B是一个q*r的
矩阵,其乘机C=AB是一个p*r的矩阵,总共需要pqr次数乘。
假如有3个矩阵的尺寸分别为10*100,100*5和5*50。若以(A0A1)A2这种方式计算,3个矩
阵的连乘积需要的数乘次数为7500。若以A0(A1A2)这种方式计算,所需的数乘次数为75000
。显然,在即算矩阵连乘积时,加括号方式对计算量有很大影响。
 
我们假设m[i][j]为 计算子成绩的代价 A i..k 和 A k+1..j 的代价,再加上这两个矩阵相乘的代价
的最小值。
 
即 m[i][j]=  min(m[i][[k]+m[k+1][j]+p[i-1]p[k]p[j])  当然这是i!=j的情况。 如果i=j 意味着
只有一个矩阵自然就没什么可以分的了。 所以 m[i][j]=0
 
即   m[i][j]=     min(m[i][k]+m[k+1][j]+p[i-1]p[k]p[j])   i<j
                      0                                                      i=j
 
大家注意到了问题中最优解包含着其子问题的最优解,这就是动态规划求解的显著特征啦!
 
另外我们在动态规划的过程中用 s[i][j] 数组记录 m[i][j]断开的位置 k,后面即可通过动态
规划构造出相应的最优解。
 
 
下附上代码
 
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int MAX=1010;
int p[MAX],m[MAX][MAX],s[MAX][MAX];
int n;
void MATRIX_CHAIN_ORDER()
{
    for(int i=0;i<=n;i++)
    {
        m[i][i]=0;
    }
    for(int l=2;l<=n;l++)//矩阵链表长度
        for(int i=1;i<=n-l+1;i++)
        {
            int j=i+l-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(t<m[i][j])
                {
                    m[i][j]=t;
                    s[i][j]=k;
                }
            }
        }
}
void PRINT_OPTIMAL_PARENS(int i,int j,int tot)
{
    if(i==j)
    {
        cout<<"A"<<i-1;
        return;
    }
    if(tot!=1)
        cout<<"(";
    PRINT_OPTIMAL_PARENS(i,s[i][j],tot+1);
    //cout<<"s"<<s[i][j]<<endl;
    PRINT_OPTIMAL_PARENS(s[i][j]+1,j,tot+1);
    if(tot!=1)
        cout<<")";
}
int main()
{
    while(cin>>n&&n)
    {
        for(int i=0;i<=n;i++)
        {
            cin>>p[i];
        }
        MATRIX_CHAIN_ORDER();
        PRINT_OPTIMAL_PARENS(1,n,1);
        cout<<endl;
    }
    return 0;
}

 

posted on 2014-04-25 09:10  东南枝DP  阅读(1872)  评论(0编辑  收藏  举报

导航