当前位置: 首页 > news >正文

矩阵链相乘的最少乘法次数(动态规划解法)

矩阵链相乘问题是动态规划的经典应用场景。当多个矩阵相乘时,不同的相乘顺序会导致乘法运算的总次数差异巨大。我们的目标是找到一种相乘顺序,使得总的乘法次数最少。

问题分析

假设有矩阵序列 A1​,A2​,…,An​,其中 Ai​ 的维度为 pi−1​×pi​。矩阵相乘满足结合律,但不同的结合方式会影响乘法运算的总次数。例如,三个矩阵 A(10×30)、B(30×5)、C(5×60),按 (AB)C 计算的乘法次数为 10×30×5+10×5×60=4500,按 A(BC) 计算的乘法次数为 30×5×60+10×30×60=27000,显然前者更优。


矩阵相乘的基本逻辑

当我们有一组维度数据,比如 74 16 58,它能构成两个矩阵:矩阵 a 的维度是 [74,16](对应数据的第 i 和 i+1 个元素),矩阵 b 的维度是 [16,58](对应数据的第 i+1 和 i+2 个元素)。

矩阵 a 和 b 相乘时,乘法次数的计算方式为 74×58×16。相乘之后,会得到一个新的矩阵,其维度为 [74,58],后续可继续与其他矩阵相乘。


问题核心:寻找最少乘法次数

我们的目标是,对于由 n 个矩阵组成的链,找到一种相乘顺序,使得总的乘法次数最少。

以包含 6 个维度数据(对应 5 个矩阵 a b c d e)的情况为例:

  • 两个矩阵相乘时,只有 1 种组合情况(如 ab)。
  • 三个矩阵相乘时,有 2 种组合情况(如 a(bc) 或 (ab)c)。
  • 四个矩阵相乘时,有 3 种组合情况(如 a(bcd)、(ab)(cd) 或 (abc)d)。
  • 以此类推,n 个矩阵相乘时,会有 n−1 种组合情况。

可以发现,不管有多少个矩阵相乘,每种组合情况都是将所有矩阵分成两部分。这一特性表明,矩阵链相乘问题具有最优子结构,非常适合用动态规划来解决。

动态规划的思路推导

以 4 个矩阵(对应 5 个维度数据 74 16 58 58 88)的情况为例,这 4 个矩阵分别是 a[74,16]、b[16,58]、c[58,58]、d[58,88]。

1. 设定断点分割矩阵链

我们可以设定一个断点 k(范围是 1 到 n),表示在第 k 个矩阵后将整个矩阵链隔开。

比如,当断点 k=2 时,矩阵链被分成两部分:ab 和 cd。

2. 子问题的最少乘法次数计算
  • 计算 ab 部分的最少乘法次数:ab 相乘的次数为 74×58×16,得到新矩阵维度为 [74,58],这部分的最少次数用 dp[1][2] 表示(dp[i][j] 表示从第 i 个矩阵到第 j 个矩阵相乘的最少次数)。
  • 计算 cd 部分的最少乘法次数:cd 相乘的次数为 58×88×58,得到新矩阵维度为 [58,88],这部分的最少次数用 dp[3][4] 表示。
3. 整体最少乘法次数的计算

此时,整个矩阵链 abcd 的最少乘法次数 dp[1][4] 就等于 ab 部分的最少次数 dp[1][2] 加上 cd 部分的最少次数 dp[3][4],再加上将这两部分结果矩阵相乘的次数 74×88×58(即 i×(j+1)×(k+1),其中 i=1,j=4,k=2)。

再比如,当断点 k=1 时,矩阵链被分成 a 和 bcd 两部分:

  • a 是单个矩阵,无需计算乘法次数。
  • 对于 bcd 部分,又存在多种分割情况(如 b(cd) 或 (bc)d),需要先求出 bcd 部分的最少乘法次数 dp[2][4](取这些分割情况中的最小值)。
  • 最后,整个矩阵链 abcd 的最少乘法次数 dp[1][4] 等于 bcd 部分的最少次数 dp[2][4] 加上将 a 与 bcd 结果矩阵相乘的次数 i×(j+1)×(k+1)(其中 i=1,j=4,k=1)。

四、核心公式与递推过程

通过对各种分割情况的分析,我们可以总结出状态转移公式
dp[i][j] = min​{dp[i][k] + dp[k+1][j] + nums[i]×nums[j+1]×nums[k+1]}

其中,nums 是存储矩阵维度的数组,dp[i][j] 表示从第 i 个矩阵到第 j 个矩阵相乘的最少次数。

递推过程是:

  1. 先计算长度为 2 的矩阵链的最少乘法次数(如 dp[1][2]、dp[2][3] 等)。
  2. 基于长度为 2 的结果,计算长度为 3 的矩阵链的最少乘法次数(如 dp[1][3]、dp[2][4] 等)。
  3. 以此类推,逐步计算更长的矩阵链,每次都取当前所有可能分割情况中的最少乘法次数,直到得到整个矩阵链(从第 1 个到第 n 个矩阵)的最少乘法次数 dp[1][n]。

代码实现

#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>  // 用于INT_MAX的定义
using namespace std;// 计算矩阵链相乘的最少乘法次数
// nums:存储矩阵维度的数组,nums[1..n]有效,对应n-1个矩阵
// n:维度数组的长度(矩阵数量为n-1)
void matrixChainMinMultiplications(vector<int>& nums, int n) {// dp[i][j]表示第i个矩阵到第j个矩阵相乘的最少乘法次数vector<vector<int>> dp(n, vector<int>(n, 0));// 遍历矩阵链的长度,从2开始(至少需要2个矩阵才能相乘)for (int length = 2; length <= n - 1; ++length) {// 遍历所有可能的起始矩阵ifor (int i = 1; i + length - 1 <= n - 1; ++i) {int j = i + length - 1;  // 计算对应的结束矩阵jdp[i][j] = INT_MAX;      // 初始化为最大整数,用于后续取最小值// 遍历所有可能的分割点k,寻找最优分割for (int k = i; k < j; ++k) {// 状态转移:当前分割的乘法次数 = 左半部分最少次数 + 右半部分最少次数 + 当前分割的乘法次数dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + nums[i] * nums[j + 1] * nums[k + 1]);}}}// 输出从第1个矩阵到第n-1个矩阵相乘的最少乘法次数cout << dp[1][n - 1] << endl;
}int main() {int n;// 多组数据输入,直到输入结束while (cin >> n) {vector<int> nums(n + 1);  // 维度数组,索引1到n有效for (int i = 1; i <= n; ++i) {cin >> nums[i];}matrixChainMinMultiplications(nums, n);}return 0;
}

代码注释说明

  • matrixChainMinMultiplications 函数:核心动态规划逻辑,计算矩阵链相乘的最少乘法次数。
    • 首先初始化 dp 数组,dp[i][j] 表示第 i 到第 j 个矩阵相乘的最少次数。
    • 外层循环按矩阵链长度 length 递增遍历,确保先计算短链,再利用短链结果计算长链。
    • 中层循环遍历所有可能的起始矩阵 i,并计算对应的结束矩阵 j
    • 内层循环遍历分割点 k,通过状态转移方程更新 dp[i][j] 为最小值。
  • main 函数:处理多组输入数据,读取矩阵维度数组并调用核心函数计算结果。
  • 示例运行

    输入

    6
    10 1 50 50 20 5

        输出:      

33000

这种动态规划方法的时间复杂度为 O(n3),空间复杂度为 O(n2),能够高效解决矩阵链相乘的最少乘法次数问题。

http://www.xdnf.cn/news/1308151.html

相关文章:

  • 开源 Arkts 鸿蒙应用 开发(十七)通讯--http多文件下载
  • bilibili视频总结
  • RK3568 NPU RKNN(一):概念理清
  • 【P14 3-6 】OpenCV Python——视频加载、摄像头调用、视频基本信息获取(宽、高、帧率、总帧数)
  • 10-verilog的EEPROM驱动-单字节读写
  • 罗技MX Anywhere 2S鼠标修复记录
  • 多机编队——(6)解决机器人跟踪过程中mpc控制转圈问题
  • AT89C52单片机介绍
  • CVE-2024-28752漏洞复现
  • mysql一启动就挂的解决
  • Javar如何用RabbitMQ订单超时处理
  • Docker部署 Neo4j Community【拒绝国内镜像拉取异常】
  • Vue组件生命周期钩子:深入理解组件的生命周期阶段
  • 论文学习24:Boundary-Sensitive Segmentation of SmallLiver Lesions
  • 服务器可以ping通,但部署的网站打不开
  • [Linux] Linux tar文档管理 系统间复制文档
  • Android 移动端 UI 设计:前端常用设计原则总结
  • 使用openssl创建自签名CA并用它签发服务器证书
  • c# WebAssembly,在网页上能运行多线程,异步,锁,原子加,减等代码吗
  • tailscale远程服务器连接局域网方案(解决境外服务器网速慢的问题)
  • OBOO鸥柏丨75寸/86平板企业办公会议触控一体机核心国产化品牌招投标参数
  • 企业运维规划及Linux介绍虚拟环境搭建
  • Jenkins Pipeline中参数化构建
  • 5 索引的操作
  • 惠普声卡驱动win10装机完成检测不到声卡
  • 每日任务day0816:小小勇者成长记之符文羊皮卷
  • ML307C 4G通信板:工业级DTU固件,多协议支持,智能配置管理
  • AI热点周报(8.10~8.16):AI界“冰火两重天“,GPT-5陷入热议,DeepSeek R2模型训练受阻?
  • c#Blazor WebAssembly在网页中多线程计算1000万次求余
  • MongoDB 聚合提速 3 招:$lookup 管道、部分索引、时间序列集合(含可复现实验与 explain 统计)