这类题目体现了DP的实质,也是经典问题。(•̀˓◞•́)
假设我们要用标准的矩阵乘法计算M1M1、M2M2、M3M3的乘积M1M2M3M1M2M3,这三个矩阵的维数分别是2x10,10x2,2x10。
- 如果我们先把M1M1和M2M2相乘,然后把结果和M3M3相乘,即((M1M2)M3)((M1M2)M3)。那么要进行2x10x2+2x2x10=80次乘法;
- 如果我们先乘M2M2M3M3,结果再与M1M1相乘,即(M1(M2M3))(M1(M2M3))。那么数量乘法的次数就变成了:10x2x10+2x10x10=400。
可见,矩阵链相乘时的顺序不同,运算量也不同。而我们的目的是找到一种乘法顺序使得运算量最小。
递推关系式
我们注意到,对于矩阵链M1M2...MiM1M2...Mi,矩阵MiMi的列数一定等于矩阵Mi+1Mi+1的行数(1≤i<n1≤i<n),这是由矩阵乘法的定义决定的。
因此,对于一个矩阵链,我们指定每个矩阵的行数和最右面矩阵MnMn的列数就可以了。假设有n+1维数r1,r2,...,rn+1r1,r2,...,rn+1,这里riri表示矩阵MiMi的行数(1≤i≤n1≤i≤n),rn+1rn+1表示最矩阵MnMn的列数。
以后,我们用Mi,jMi,j来记MiMi+1...MjMiMi+1...Mj的乘积。用C[i][j]C[i][j]来记录链Mi,jMi,j数量乘法的次数。
对于给定的一对索引ii和,Mi,jMi,j可用如下方法计算:
设kk是和jj之间的一个索引,索引把矩阵链Mi,jMi,j分成了两部分:Mi,k−1=MiMi+1...Mk−1Mi,k−1=MiMi+1...Mk−1和Mk,j=MkMk+1...MjMk,j=MkMk+1...Mj。所以Mi,j=Mi,k−1Mk,jMi,j=Mi,k−1Mk,j。
用这种方法计算Mi,jMi,j的耗费(即数量乘法的次数),是计算Mi,k−1Mi,k−1的耗费加上计算Mk,jMk,j的耗费再加上Mi,k−1Mi,k−1乘以Mk,jMk,j的耗费(它是rirkrj+1rirkrj+1)。
我们需要遍历kk,找到使乘法所需的数量乘法最小的kk值,我们有以下递推式:
Mini<k≤jMini<k≤j{C[i][k−1]+C[k][j]+rirkrj+1}{C[i][k−1]+C[k][j]+rirkrj+1}
为了找出M1M2..MnM1M2..Mn的乘法次数,我们只需要解递推式:
C[1][n]=C[1][n]=Min1<k≤nMin1<k≤n{C[1][k−1]+C[k][n]+rirkrn+1}{C[1][k−1]+C[k][n]+rirkrn+1}
填表
假设我们要求n=6n=6个矩阵相乘。考虑下图:

对角线dd用乘出各种个相继矩阵的最小耗费填满。特别地,对角线5恰好由一项组成,它表示6个矩阵相乘的最小耗费,这就是我们要求的结果。
我们从对角线0开始,到对角线5为止,沿着对角线填充这个三角形表。
- 首先在对角线0中,每个链仅由一个矩阵的组成,没有数量乘法,因此这个对角线填0。
- 接着,对角线1由两个连续的矩阵相乘的耗费来填充。如C[2][3]用M2M3M2M3的乘法耗费来填。
- 余下的对角线根据上面的递推式和先前存储在表中值来填。举例来说,C[2][5]的值为以下三个耗费的最小值:
– (1)计算M2,2M2,2的耗费(即C[2][2])加上计算M3,5M3,5(即C[3][5])的耗费,再加上M2,2M2,2乘以M3,5M3,5的耗费。
– (2)计算M2,3M2,3的耗费(即C[2][3])加上计算M4,5M4,5(即C[4][5])的耗费,再加上M2,3M2,3乘以M4,5M4,5的耗费。
– (3)计算M2,4M2,4的耗费(即C[2][4])加上计算M5,5M5,5(即C[5][5])的耗费,再加上M2,4M2,4乘以M5,5M5,5的耗费。
伪代码
下面我们给出算法的伪代码实现
MATCHAIN
输入:n个矩阵的链的维数对应于正整数数组r[1...n+1]r[1...n+1],其中,r[1...n]r[1...n]是n个矩阵的行数,r[n+1]r[n+1]是MnMn的列数。
输出:n个矩阵相乘的数量乘法的最小次数。
for i=1 to n {填充对角线d0}
C[i,i]=0;
end for
for d=1 to n-1 {填充对角线d1到dn-1}
for i=1 to n-d {填充对角线di的项目}
j=i+d
comment:下列三行计算C[i,j]
C[i,j]=inf
for k=i+1 to j
C[i,j]=Min{C[i,j],C[i,k-1]+C[k,j]+r[i]*r[k]*[j+1]
end for
end for
end for
return C[1,n]
时空复杂度
对于某个常数c>0,算法的运行时间正比于:
因此算法的时间复杂度是Θ(n3)Θ(n3)
显然,算法所需要的内存空间取决于所需要的三角数组的大小,也就是Θ(n2)Θ(n2)。
这篇博客详细讲解了动态规划在解决矩阵链相乘问题中的应用,通过递推关系式、填表方法和伪代码阐述了如何寻找最优乘法顺序以减少运算量。并分析了算法的时间和空间复杂度。

1万+

被折叠的 条评论
为什么被折叠?



