矩阵链乘问题

Posted 小螺号打豆豆

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了矩阵链乘问题相关的知识,希望对你有一定的参考价值。

矩阵链乘问题

应用动态规划

给定n个矩阵的序列Ai , 计算A1A2A3*...An. 矩阵乘法满足结合律,乘法的计算顺序不同,需要计算的次数就不同,

  • 假设A1是pq的矩阵A2是qr的矩阵,那么计算A1A2的结果需要计算pq*r次
  • 计算A1A2A3 A1(10100) A2(1005) A3(550) 如果按照(A1A2)A3计算,需要计算次数是101005 + 105*50 = 7500次
  • 如果按照A1(A2A3)计算,需要计算次数是 100550 + 1010050 = 75000次
  • 不同的计算顺序计算效率可能会差10倍

矩阵链乘可以描述为:给定n个矩阵的链,给定一个括号化方案,使得矩阵乘法次数最少

动态规划的第一步是确定最优子结构

对Ai....Aj求最佳括号化,必然要在中间加一个分割点,原序列转化为两个子序列Ai..Ak , Ak+1..Aj
设d[i,j]表示计算链i~j所需的最小代价
原问题的代价 = Ai..Ak 的代价 + Ak+1..Aj + 两者相乘的代价
d[i][j] = d[i][k] + d[k+1][j] + p[k-1] * p[k] * p[k+1] k in (i,j)
如何利用最优子结构的性质 从子问题的最优解构造出原问题的最优解?
每个子问题的求解都要划分链,找到子问题最优的划分点,然后将子问题的最优解合并起来。
设s[i,j]记录子链i~j的最优划分点的位置,那么s[1,n]将链划分为两个子链,如此递归的划分,就得到了原问题的最优划分方案,

状态转移代码

void MATRIX_CHAIN_ORDER()
{
    for(int i=1;i<=n;i++) 
        d[i][i] = 0;
    
    for(int l=1;l<n;l++)
    {
        for(int i=1;i+l<=n;i++)
        {
            int j = i+l;
            d[i][j] = INF;
            for(int k =i;k<j;k++)
            {
                int mid = d[i][k] + d[k+1][j] + p[k-1]*p[k]*p[k+1];
                if(mid<d[i][j])
                {
                    d[i][j] = mid;
                    s[i][j] = k;
                }
            }
        }
    }
}

如此,计算出了每个区间的最优划分点。时间复杂度O(n^3)

最后一步:构造最优解

根据每个区间的最优划分点还原出结果

void mer(int x,int y)
{
    if(x>y)return;
    if(x==y)printf("A%d",x);
    else {
        printf("(");
        mer(x,s[x][y]);
        printf("*");
        mer(s[x][y]+1,y);
        printf(")");
    }
}

以上是关于矩阵链乘问题的主要内容,如果未能解决你的问题,请参考以下文章

矩阵链乘最优化实现

矩阵链乘

矩阵链乘(递归求解)

矩阵最优链乘及Java实现

矩阵链乘

UVa 442 矩阵链乘