首页 > 代码库 > [CLRS][CH 15.2] 动态规划之矩阵链乘法

[CLRS][CH 15.2] 动态规划之矩阵链乘法

摘要

整理了矩阵链乘法的动态规划思路。

题目

给定n个要相乘的矩阵构成的序列<A1, A2, ... , An>,其中 i=1, 2, ..., n,矩阵 Ai 的维数为pi-1*pi。计算乘积 A1A2...A的最小代价的矩阵相乘循序。

补充:矩阵乘法满足结合律,例如,乘积 A1A2A3A共有五种不同加括号结合形式。不同的结合形式极大的影响运算效率。当且仅当矩阵A和B相容(A.列 = B.行)时,才可以计算矩阵乘法。例如:矩阵A为p*q, 矩阵B为q*r,则相乘后得到的矩阵C为p*r。计算C的时间为pqr。下面给出矩阵相乘计算伪代码:

; 计算矩阵A, B乘积, rows和columns分别为行和列MATRIX-MULTIPLY(A, B)if (columns[A] != rows[B])    error "Incompatible Dimensions."else {    for i = (1 to rows[A])        for j = (1 to columns[B])            C[i, j] = 0;                for k = (1 to columns[A])                    C[i, j] = C[i, j] + A[i, k] * B[k, j]    return C}

思路

计算全部括号的重数

设P(n)表示一串n个矩阵可能的全部加括号方案数。当n=1时,只有一个矩阵,因此只有一种方案;当n>=2时,一个加全部括号的矩阵乘积,就是两个加全部括号的矩阵子乘积的乘积。而且这两个子乘积之间的分裂可能发生在第k个和第(k+1)个矩阵之间,其中k = 1, 2, ..., n-1。因此可得递归式:

$P(n)= \begin{cases} 1 & n=1\\ \sum_{k=1}^{n-1}{P(k)P(n-k)} & n\geqslant2 \end{cases}$

步骤1: 最优加全部括号的结构

动态规划的第一步就是找最优子结构,然后利用子问题最优解构造原问题最优解。对于本体而言,最优子结构如下:

假设 A1Ai+1...A的一个最优加全部括号形式把乘积在 AkAk+1 之间分开,则对于原式 A1Ai+1...A的最优加全部括号的前半部分 A1Ai+1...A的加全部括号形式必须是 A1Ai+1...A的一个最优解。后半部分同理。

因此我们得到最优子结构构造最优解。已经得出:一个矩阵链乘法的最优解需要分割乘积,因此可以讲原问题分割成两个子问题寻找最优解,最后合并。必须保证在寻找一个正确的位置分割时,已经考虑过所有可能的位置,从而确保已检查过了最优的解法。

步骤2: 一个递归解

设 m[i, j] 为计算矩阵 Ai..j 的最优解,即所需标量乘法次数最小值,对于整个问题,最优解即为 m[1, n]。易得对于乘积 Ai..j 递归方程:

$\textrm{m}[i,j]=\begin{cases}0&i=j\\\min_{i\leq k<j}(\textrm{m}[i,k]+\textrm{m}[k+1,j]+p_{i-i}p_{k}p_{j})&i<j\end{cases}$

为了追踪如何构造最优解,定义 s[i,j] 为这样一个k值,在该处分裂乘积后可得一个最优解。亦即 s[i,j] 等于使 $\textrm{m}[i,j]=\textrm{m}[i,k]+\textrm{m}[k+1,j]+p_{i-1}p_{k}p_{j}$ 的k值。

步骤3: 计算最优代价

我们使用自底向上的表格法来计算最优代价。下面的代码中包括如下数据:
设矩阵 A的维数为 pi-1*p, i = 1, 2, ..., n。
输入序列为 p = <p0, p1, ... , pn>,其中 length[p] = n + 1。
使用一个辅助表 m[1..n, 1..n] 来保存 m[i, j] 的代价。
使用一个辅助表 s[1..n, 1..n] 来计算 m[i, j] 时取得最优代价处k的值。利用表格s来构造一个最优解。

为了正确实现自底向上,必须确定哪些表项用来计算 m[i, j] 。计算 m[i, j] 的公式说明计算一个有 j-i+1 个矩阵的矩阵链乘积时,代价 m[i, j] 仅依赖于计算一个有少于 j-i+1 个矩阵的矩阵链乘积的代价。也就是说,对于 k = i, i+1, i+2, ..., j-1,矩阵 Ai..k 是 k-i+1 < j-i+1 个矩阵的乘积,矩阵 Ak+1..j 是 j-k < j-i+1 个矩阵的乘积。因此,该算法填表m的方式对应于求解按长度递增的矩阵链上的家全部括号问题。

MATRIC-CHAIN-ORDER(p)n = length[p] - 1for i = (1 to n) ; 该循环令 m[i,i] = 0, 即长度为1的链的最小代价    m[i, i] = 0for l = (2 to n) ; l为链的长度, 循环计算长度为(2..n)的链的最小代价    for i = (1 to n-l+1)        m[i, j] =for k = (i to j-1)            q = m[i,k] + m[k+1,j] + p(i-1)p(k)p(j)                if q < m[i,j]                    m[i,j] = q, s[i,j] = kreturn m and s

 

[CLRS][CH 15.2] 动态规划之矩阵链乘法