矩阵链相乘问题

问题描述

  给定n个矩阵A1,A2 ,...,An,相邻的矩阵是可乘的,如何确定一个最优计算次序,使得以此次序计算需要的数乘次数最少?



计算次序对计算性能的影响:

  假设n=3,A1,A2,A3的维数分别为10×100,100×5,5×50。考察A1×A2×A3需要的数乘次数,有以下

两种计算方式:

  (1)(A1×A2)×A3:10×100×5+10×5×50=7500

  (2) A1×(A2×A3):100×5×50+10×100×50=75000

通过这个简单的例子足以说明,矩阵的计算次序对计算性能的影响极大。

 



  

分析:

1.最优解的结构

  将矩阵乘积AiAi+1...Aj记为A[i:j],要求计算A[1:n]的最优计算次序,假设将这个矩阵链断开,分为两个子

矩阵链的乘积也就是(AiAi+1...Ak)(Ak+1...Aj),先计算A[i:k]和A[k+1,j],然后将计算结果相乘得到A[i:j].

这样,A[i:j]的计算量就等于A[i:k]和A[k+1:j]的计算量与A[i:k]与A[k+1:j]两个矩阵相乘的计算量。

  关键的一点是,如果找到了一种A[1:n]的最优计算次序,那么以这个次序计算A[1:k]与A[k+1:n]的也是

最优的。用反证法说明,如果有一个子数组不是最优的,那么可以找到使原问题最优的次序。

2.建立子问题与原问题解的联系

  在计算得到子问题的解后,要想办法将子问题的解进行组合,以得到原问题的解。

  假设A[i:j]在最优计算次序的情况下需要的乘法次数用m[i][j]来表示。在计算A[i:j]时,将矩阵链断开,

得到A[i:k]和A[k+1:j]两个矩阵链,分别计算出它们在最优次序下的乘法次数m[i][k]和m[k+1][j],然后加上

矩阵A[i:k]和A[k+1:j]相乘所需要的乘法次数。用向量p来表示矩阵的维度,矩阵Ai的维度是pi-1×pi。

  我们通过将矩阵链A[i:j]划分为较小的矩阵链A[i:k]和A[k+1:j]来计算A[i:j]的最优值,这样的划分方式如上图所示,

共有j-i种。

  通过上面的分析,可以得到如下的递推关系

  

m[i][j]给出了最优值,即计算A[i:j]所需的最少乘法次数。同时,还确定了该最优次序对应的断开位置k:

  m[i][j] = m[i][k] + m[k+1][j] + pi-1pkpj

将得到每个子矩阵链时的断开位置k记录下来,就可以构造出最优次序。



计算过程(以长度为4的矩阵链为例)

递归树如下:

  图中有边相连表示在计算上层结点时需要使用到下层子问题的结果进行组合,采用自底向上的方法,先计算简单子问题的结果,再

利用递推关系式最终得到原问题的结果。



部分代码

1.寻找最优次序

static void matrix_chain(int *dim,int **m,int **s,int n)
{
    for(int i=1;i<=n;i++)
        m[i][i]=0;
    for(int r=2;r<=n;r++)
        for(int i=1;i<=n-r+1;i++){
            int j=r+i-1;
            m[i][j]=m[i+1][j]+dim[i-1]*dim[i]*dim[j];
            s[i][j]=i;
            for(int k=i+1;k<j;k++){
                int t=m[i][k]+m[k+1][j]+dim[i-1]*dim[k]*dim[j];
                if(t<m[i][j]){
                    m[i][j] = t;
                    s[i][j] = k;
                }
            }
        }
}

用n+1维向量dim来表示n个矩阵的维度,用矩阵m来保存计算子问题时得到的子问题的最优解,以减少计算次数,矩阵s用来保存每个子问题的最优断开位置k

2.用保存的数组s来构造最优次序

void trace_back(int **s,int start,int end)
{
    if(start == end)
        return;
    trace_back(s,start,s[start][end]);
    trace_back(s,s[start][end]+1,end);
    printf("A(%d,%d)xA(%d,%d)\n",start,s[start][end],s[start][end]+1,end);
}
时间: 2024-07-31 14:29:18

矩阵链相乘问题的相关文章

算法导论 之 动态规划 - 矩阵链相乘

1 引言 在大学期间,我们学过高等数学中的线性规划,其中有关于矩阵相乘的章节:只有当矩阵A的列数与矩阵B的行数相等时,A×B才有意义.一个m×n的矩阵A(m,n)左乘一个n×p的矩阵B(n,p),会得到一个m×p的矩阵C(m,p).矩阵乘法满足结合律,但不满足交换律. 假设现要计算A×B×C×D的值,因矩阵乘法满足结合律,不满足交换律,即:A.B.C.D相邻成员的相乘顺序不会影响到最终的计算结果,比如: A×(B×(C×D)).A×((B×C)×D).(A×B)×(C×D).A×(B×C)×D.

UVA 348 &amp; ZOJ 1276 Optimal Array Multiplication Sequence(dp , 矩阵链相乘问题)

Optimal Array Multiplication Sequence Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Description Given two arrays A and B, we can determine the array C = AB using the standard definition of matrix multiplication: The number of

矩阵链相乘实例

题目描述 零崎有很多朋友,其中有一个叫jhljx. jhljx大家很熟悉了,他数学不好也是出了名的,大家都懂. 现在jhljx遇到了矩阵乘法,他当时就懵了.数都数不清的他,矩阵乘法怎么可能会算的清楚呢?虽然零崎觉得还不如让你们来算,不过好歹也要给jhljx个面子,给她留下一个证明自己数学实力的机会.为了减小jhljx的计算量,让他赶快算出不正确答案来(估计他算上几遍都不一定能出一个正确答案),零崎请你们帮助jhljx. 输入 多组输入数据. 每组数据以N开始,表示矩阵链的长度.接下来一行N+1个

算法导论--矩阵链相乘

#include<iostream> using namespace std; /* 计算括号化方案数:标量乘法作为代价衡量,应该使标量乘法尽可能少. m[i,j]表示Ai.....Aj所需标量乘法的最小值. i=j 时只有一个矩阵,无需分割 m[i,i]=0; 采用自底向上的方式: */ int m[100][100]; int p[]={30,35,15,5,10,20,25}; int bottomcut(int n){ int t; for(int l=2;l<=n;l++){

动态规划-矩阵链乘法

问题描述: 给定由n个要相乘的矩阵构成的序列(链)<A1,A2,...,An>,要计算乘积A1A2...An,可以将两个矩阵相乘的标准算法作为一个子程序,通过加括号确定计算的顺序(对同一矩阵链,不同的计算顺序所需要的计算次数大不相同). 目标问题:给定n个矩阵构成的矩阵链<A1,A2,...,An>,其中,i=1,2,...,n,矩阵Ai的维数为pi-1×pi,对乘积A1A2...An以一种最小计算次数加全部括号. 穷尽搜索: 令P(n)表示一串n个矩阵可能的加全部方案数.当n=1

矩阵链乘最优化实现

矩阵链乘最优化算法(括号化算法),关键要找到A[i]...A[j]矩阵链相乘做最少乘法次数(存在m[][]中)的相乘顺序,记录在矩阵s[][]中.再利用递归定义矩阵链乘算法.递归的出口是只有一个矩阵(直接返回)或者两个矩阵(返回相乘后的结果矩阵)的情况. 1 //#include"OptimalMatrixMultiplication.h" 2 #include<iostream.h> 3 #include<stdio.h> 4 #include<stdl

动态规划之矩阵链乘法

矩阵链相乘 矩阵链乘法 求解矩阵链相乘问题时动态规划算法的另一个例子.给定一个n个矩阵的序列(矩阵链)<A1,A2,...,An>,我们希望计算它们的乘积 A1A2...An ?两个矩阵A和B只有相容(compatible),即A的列数等于B的行数时,才能相乘.如果A是p×q的矩阵,B是q×r的矩阵,那么乘积C是p×r的矩阵.计算C所需要时间由第8行的标量乘法的次数决定的,即pqr. ? ?以矩阵链<A1,A2,A3>为例,来说明不同的加括号方式会导致不同的计算代价.假设三个矩阵的

动态规划之矩阵链

dp有很多个经典应用,矩阵链是其中一个. 对于我这种数学不好的人,需要回顾矩阵性质. 若矩阵A的维数是p×q,矩阵B的维数是q×r,则A与B相乘后所得矩阵AB的维数是p×r.按照矩阵相乘的定义,求出矩阵AB中的一个元素需要做q次乘法(及q-1次加法).这样,要计算出AB就需要做p×q×r次乘法.由于加法比同样数量的乘法所用时间要少得多,故不考虑加法的计算量. 看下面一个例子,计算三个矩阵连乘{A1,A2,A3}:维数分别为10*100 , 100*5 , 5*50 按此顺序计算需要的次数((A1

UVa 442 矩阵链乘及scanf说明符中的\n

题目:计算题给矩阵相乘次序所需的相乘次数.   我们已知的m*n和n*k矩阵相乘,得到的是m*k矩阵,但需要的相乘次数是m*n*k(开始当成了m*k %>_<%).evaluate,求值 思路:每个矩阵用结构体表示,有名字.行.列.需要计算的次数.矩阵相乘的过程用栈来模拟.遇到左括号(,压栈这是自然的.遇到一个矩阵时,检查栈顶,如果栈顶元素是左括号,则压栈,否则就是矩阵,则比较栈顶矩阵和输入矩阵是否匹配,如果匹配则修改栈顶矩阵的列.计算次数,这样输入矩阵对栈顶进行了修改,相当于完成了相乘,这时