📜  矩阵链乘法问题中的打印括号(1)

📅  最后修改于: 2023-12-03 15:27:17.854000             🧑  作者: Mango

矩阵链乘法问题中的打印括号

什么是矩阵链乘法问题?

矩阵链乘法问题是计算矩阵乘法的一种特殊情况,即给定 $n$ 个矩阵 $A_1,A_2,...,A_n$,它们的维数分别为 $p_0 \times p_1, p_1 \times p_2,...,p_{n-1} \times p_n$,求它们乘积 $A_1A_2...A_n$ 的最小代价及其计算顺序。

其中,矩阵乘法的代价定义为两个矩阵相乘的标量乘法次数。

如何求解矩阵链乘法问题?

矩阵链乘法问题可以使用动态规划的方法进行求解,具体过程如下:

  1. 定义状态:设 $m_{i,j}$ 表示计算矩阵 $A_iA_{i+1}...A_j$ 的最小代价。
  2. 初始化状态:对于任意的 $i=i$,都有 $m_{i,i}=0$。
  3. 状态转移方程:假设 $k$ 是区间 $[i,j]$ 中最后一个被乘的矩阵,即计算矩阵 $A_iA_{i+1}...A_j$ 时最后一次乘法是在 $A_kA_{k+1}$ 处进行的,那么有:

$$ m_{i,j} = \min_{i \leq k < j} {m_{i,k} + m_{k+1,j} + p_{i-1} \times p_k \times p_j } $$

  1. 最终结果:$A_1A_2...A_n$ 的最小代价为 $m_{1,n}$。
如何打印括号序列?

除了求解最小代价外,矩阵链乘法问题中还有一个重要的问题,就是如何打印出对应的最优括号序列。

这个问题可以通过在求解最小代价时记录决策的位置 $k$,然后根据括号的计算顺序进行递归打印得到。

具体实现可以参考下面的 Python 代码:

def print_optimal_parens(s, i, j):
    if i == j:
        print("A" + str(i), end="")
    else:
        print("(", end="")
        print_optimal_parens(s, i, s[i][j])
        print_optimal_parens(s, s[i][j] + 1, j)
        print(")", end="")

n = 6
p = [30, 35, 15, 5, 10, 20, 25]

m = [[0 for _ in range(n)] for _ in range(n)]
s = [[0 for _ in range(n)] for _ in range(n)]

for l in range(2, n + 1):
    for i in range(n - l + 1):
        j = i + l - 1
        m[i][j] = float("inf")
        for k in range(i, j):
            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] = k

print_optimal_parens(s, 1, n - 1)  # ((A1(A2(A3(A4(A5A6))))))

参考资料
  • Introduction to Algorithms, Third Edition
总结

矩阵链乘法问题中的打印括号是该问题的一个重要扩展,通过递归打印括号序列,可以更好地理解矩阵链乘法问题的求解过程和最优决策的思路。