问题:使用动态规划方法,求解如下矩阵连乘问题:已知有4个矩阵, 每个矩阵Ak (k=1,2,3,4)为rk×r(k+1),其中r1=5,r2=10,r3=3,r4=12,r5=5,求矩阵连乘积A1×A2×A3×A4的最佳乘积顺序,给出最优解和最优值。
解答(手写过程+代码实现):
代码(可执行,附结果):
def matrix_chain_order(p):
n = len(p) - 1 # 矩阵数量是维度数-1
m = [[0 for _ in range(n)] for _ in range(n)] # 存储最小计算次数
s = [[0 for _ in range(n)] for _ in range(n)] # 存储断开点
# L 是链长度,从2开始(两个矩阵的连乘)
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] * p[k + 1] * p[j + 1]
if q < m[i][j]:
m[i][j] = q
s[i][j] = k + 1 # 存储切割位置,k + 1 表示实际切割点编号
return m, s
def print_optimal_parens(s, i, j):
if i == j:
return f"A{i+1}"
else:
cut_point = s[i][j] # 获取实际切割点编号
return f"({print_optimal_parens(s, i, cut_point-1)} x {print_optimal_parens(s, cut_point, j)})"
# 测试
if __name__ == '__main__':
# 输入矩阵维度序列
p = [5, 10, 3, 12, 5] # A1: 5x10, A2: 10x3, A3: 3x12, A4: 12x5
m, s = matrix_chain_order(p)
print("最优计算次表:")
for row in m:
print(row)
print("\n切割位置表:")
for row in s:
print(row)
n = len(p) - 1
print("\n最优计算顺序:", print_optimal_parens(s, 0, n - 1))
print("最少标量乘法次数:", m[0][n - 1])
结果:

与手算结果相同。
主要逻辑:
这段代码实现了矩阵链乘法问题的动态规划解法,核心目的是在给定矩阵链的情况下,通过调整计算顺序,使矩阵乘法的标量计算次数最小。以下是具体逻辑的分步说明:
1. 问题背景
- 给定 n 个矩阵的维度序列
,其中:
- 矩阵
的维度为
。
- 矩阵
的维度为
。
- 依此类推,矩阵
的维度为
。
- 矩阵
- 目标:通过调整矩阵的计算顺序,最小化矩阵链乘法的标量计算次数。
2. 动态规划解决方案
状态定义
:从矩阵
到
的最少标量乘法次数。
:从矩阵
到
的最佳切割点,表示在哪个位置断开。
递推公式
对于矩阵链,尝试在所有可能的切割点 k(i≤k<j)处断开:
:计算
所需的最少标量乘法次数。
:计算
所需的最少标量乘法次数。
:将两个部分相乘时的标量乘法次数。
动态规划过程
- 初始化:
- 单个矩阵的计算次数为 0,即
。
- 单个矩阵的计算次数为 0,即
- 枚举链长度 L:
- L = 2:两个矩阵的连乘。
- L = 3:三个矩阵的连乘。
- …
- L = n:完整链的连乘。
- 枚举起点 i 和终点 j:
。
- 枚举切割点 kk:
- 计算每个 k 的代价 q,取最小值更新
。
- 计算每个 k 的代价 q,取最小值更新
结果回溯
- 利用
表记录最佳切割点。
- 使用递归函数
print_optimal_parens输出最优括号化顺序。
3. 输入输出说明
输入:
矩阵维度序列p = [5, 10, 3, 12, 5],对应:
- A1:5×10
- A2:10×3
- A3:3×12
- A4:12×5
输出:
-
最优计算次数表
m: 表中是从
到
的最少标量乘法次数。
[[0, 150, 330, 405], [0, 0, 360, 330], [0, 0, 0, 180], [0, 0, 0, 0]] -
切割位置表
s: 表中是从
到
的最佳切割点:
[[0, 1, 2, 2], [0, 0, 2, 2], [0, 0, 0, 3], [0, 0, 0, 0]] -
最优括号化顺序: 使用切割位置表 s 回溯得到括号化顺序:
((A1 x A2) x (A3 x A4)) -
最少标量乘法次数: 从
中得到最优值:
405
4. 算法复杂度
- 时间复杂度:
- 共有
个状态,每个状态需要计算
个切割点,总时间复杂度为
。
- 共有
- 空间复杂度:
- 动态规划表
m和s的空间需求为。
- 动态规划表
总结
- 使用动态规划表
m和s分别记录最小计算次数和切割点,避免重复计算子问题。 - 通过递归回溯生成最优括号化顺序,清晰地展示了矩阵链乘法的优化过程。
- 输出的结果包括最优括号化顺序和最少标量乘法次数,完美解决了问题。
手写过程:
动态规划过程与结果如下(其中矩阵行列标为数学表示法(从1开始)并非代码中真实行列标(从0开始),代码中行列标均-1即可):

575

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



