矩阵链相乘(动态规划)

news2025/7/20 13:17:04

【问题描述】给定n个矩阵 M 1 , M 2 . . . M n M_1,M_2...M_n M1,M2...Mn,他们的维数分别是 r 1 ∗ c 1 , r 2 ∗ c 2 . . . r n ∗ c n r_1*c_1,r_2*c_2...r_n*c_n r1c1,r2c2...rncn,要求使用【动态规划】的策略求解矩阵连乘的最优计算代价(总乘法次数最少)。题目保证矩阵相乘一定是有效的。

例如有三个矩阵 M 1 , M 2 , M 3 M_1,M_2,M_3 M1M2M3,他们的维度分别是 2 ∗ 10 , 10 ∗ 2 , 2 ∗ 10 2*10,10*2,2*10 210,102210。按照矩阵乘法的结合律,可以先把 M 1 M_1 M1 M 2 M_2 M2相乘,然后把结果和 M 3 M_3 M3相乘,总的乘法次数为 2 ∗ 10 ∗ 2 + 2 ∗ 2 ∗ 10 = 80 2*10*2+2*2*10=80 2102+2210=80次;也可以先把 M 2 M_2 M2 M 3 M_3 M3相乘,再用 M 1 M_1 M1去相乘,这种方式下总的乘法次数为 10 ∗ 2 ∗ 10 + 2 ∗ 10 ∗ 10 = 400 10*2*10+2*10*10=400 10210+21010=400次。因此最优计算代价为80。
【输入形式】输入的第1行中有1个数字 n n n,表示矩阵的个数;接下来 n n n行,每行2个整数 r i r_i ri c i c_i ci,分别表示矩阵 M i M_i Mi的行数和列数。
【输出形式】输出1行中有一个数字,表示 n n n个矩阵相乘的最优计算代价。
【样例输入】

3

2 10

10 2

2 10
【样例输出】

80
【说明】

n > = 2 n>=2 n>=2

1 < = r i , c i < = 20 1<=r_i,c_i<=20 1<=ri,ci<=20

题解:

我们定义 d p [ i ] [ j ] dp[i][j] dp[i][j]为从第 i i i个矩阵连乘到第 j j j个矩阵的最优代价,那么我们可以得到状态转移方程

∀ k ∈ [ i , j ) , d p [ i ] [ j ] = d p [ i ] [ k ] + d p [ k + 1 ] [ j ] + r [ i ] ∗ c [ k ] ∗ c [ j ] \forall k \in [i,j),dp[i][j]=dp[i][k]+dp[k+1][j]+r[i]*c[k]*c[j] k[i,j),dp[i][j]=dp[i][k]+dp[k+1][j]+r[i]c[k]c[j]

解释一下,这个方程的意思就是从第 i i i号矩阵到第 j j j号矩阵的连乘的最优代价等于 i i i个矩阵到第 k k k个矩阵的最优代价加上 k + 1 k+1 k+1到第 j j j个矩阵的最优代价再加上这两边矩阵相乘的代价,其中 k k k是大于等于 i i i且小于 j j j的一个正整数。

更通俗地来说,第 k k k个矩阵作为第 i i i号矩阵到第 j j j号矩阵的一个分割线,把整条矩阵链分成了两部分,那么总的最优代价就等于左边部分的最优代价加上右边部分的最优代价,再加上把左右两部分拼回去的代价。
请添加图片描述
相当于说,我分割好后,先把左边的矩阵链按照最优的方法计算完得到一个矩阵A,并把代价记下来,再把右边的矩阵链也按照最优的方法计算完得到另一个矩阵B,也把代价记下来,最终,将A与B相乘,这也会产生代价,最后把这三个代价相加,就得到整条矩阵链计算的代价。

但是,不同的 k k k会得到不同的代价,因此要在k的取值范围内枚举并计算将每一个 k k k作为分割线时,所产生的代价是多少,并取最小值作为整条矩阵链的最优代价。

说了这么多,可能还需要补充一下矩阵相乘的代价需要怎样计算,举例来说,一个 1 × 3 1\times3 1×3的矩阵和一个 3 × 5 3\times5 3×5的矩阵相乘所产生的计算代价就是 1 × 3 × 5 1\times3\times5 1×3×5;一个 1 × 5 1\times5 1×5的矩阵和一个 5 × 5 5\times5 5×5的矩阵相乘所产生的计算代价就是 1 × 5 × 5 1\times5\times5 1×5×5

根据以上举例,可以总结出规律:

一个 n 1 × m 1 n_1 \times m_1 n1×m1的矩阵和一个 n 2 × m 2 n_2 \times m_2 n2×m2的矩阵相乘所产生的计算代价就是 n 1 × m 1 × m 2 n_1 \times m_1 \times m_2 n1×m1×m2,当然,众所周知,两个矩阵相乘的必要条件是 m 1 = n 2 m_1=n_2 m1=n2,所以把 m 1 m_1 m1替换成 n 2 n_2 n2也是ok的。

其实这个代价仅代表的是两个矩阵相乘所需要使用乘法的次数,我们知道,矩阵相乘不仅需要乘法,也需要加法,但如果单单只是想要比较计算代价来得出最优方法,省略掉加法代价也无伤大雅。

另外,对于一个矩阵链 M 1 × M 2 × M 3 × . . . × M n M_1\times M_2 \times M_3\times...\times M_n M1×M2×M3×...×Mn来说,它的答案矩阵的规模一定是 r 1 × c n r_1\times c_n r1×cn

明确了状态转移方程的意义之后,便需要知道初始状态的情形

  • 由于矩阵本身不需要计算,因此所有的 d p [ i ] [ i ] dp[i][i] dp[i][i]都等于0
  • 考虑矩阵链中只包含两个矩阵的情形,那么 d p [ 1 ] [ 2 ] = d p [ 1 ] [ 1 ] + d p [ 2 ] [ 2 ] + r [ 1 ] ∗ r [ 1 ] ∗ c [ 2 ] dp[1][2]=dp[1][1]+dp[2][2]+r[1]*r[1]*c[2] dp[1][2]=dp[1][1]+dp[2][2]+r[1]r[1]c[2]
  • 如果我们画出 d p dp dp表可以看到 d p [ 1 ] [ 1 ] dp[1][1] dp[1][1] d p [ 2 ] [ 2 ] dp[2][2] dp[2][2]是位于 d p [ 1 ] [ 2 ] dp[1][2] dp[1][2]的左下角的,甚至来说,对于任意一个 d p [ i ] [ j ] dp[i][j] dp[i][j]来说,它的求解都需要用到它左下方的值,如果按照一般的 d p dp dp路线,从第一行开始,每一行从第一个开始向右枚举,那么 d p [ i ] [ j ] dp[i][j] dp[i][j]左下方的值根本就没有求解过,何谈根据最优子结构递推得出最优解?

因此,我们dp的路线也有所改变,具体做法代码中已给出,外层循环枚举每一条对角线 d d d,第二层循环枚举行号 i i i,根据行号 i i i和对角线号 d d d可以得出列号 t = i + d − 1 t=i+d-1 t=i+d1,最后一层循环枚举 k k k
在这里插入图片描述

代码:

#include <iostream>
using namespace std;
const int inf = 0x3f3f3f3f;
int n, r[21], c[21], dp[21][21];
//def:dp[i][j]代表从第i个矩阵到第j个矩阵的连乘的最优代价

void init() {
    for (int i = 1; i <= n; i++) {
        dp[i][i] = 0;
    }
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> r[i] >> c[i];
    }
    init();
    for (int d = 2; d <= n; d++) {
        for (int i = 1; i <= n - d + 1; i++) {
            int t = i + d - 1; dp[i][t] = inf;
            for (int k = i; k < t; k++) {
                int cost = dp[i][k] + dp[k + 1][t] + r[i] * c[k] * c[t];
                if (cost < dp[i][t]) {
                    dp[i][t] = cost;
                }
            }
        }
    }
    cout << dp[1][n];
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/35859.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker 学习视频集 bilibili

1.什么是Docker_哔哩哔哩_bilibili 2.Docker的安装_哔哩哔哩_bilibili 3.镜像、容器和仓库_哔哩哔哩_bilibili 4.在容器中部署一个应用_哔哩哔哩_bilibili 5.将容器保存成镜像成片_哔哩哔哩_bilibili 6.使用Dockerfile构建镜像1_哔哩哔哩_bilibili 7.导入导出镜像_哔哩哔…

vscode配合gitee同步云设置

更换开发设备后&#xff0c;新安装的vscode软件&#xff0c;是没有原先的配置的&#xff0c;诸如快捷键&#xff0c;快捷代码段生成、安装的各个插件&#xff0c;插件的配置等都木大了&#xff0c;开发起来会很别扭&#xff0c;网上最多的就是去安装一个叫做Settings Sync的插件…

springcloud五大核心部件

springcloud五大核心部件 一、springcloud介绍 springcloud是微服务的集大成者&#xff0c;将一系列的组件进行了整合。基于springboot构建 &#xff0c;可以快速配置常用模块并构建庞大的分布式系统。 二、具体业务分析 我们举一个例子来进行业务场景分析 假设现在开发一…

Websocket学习

参考&#xff1a;http://www.mydlq.club/article/86/ 这里写目录标题一、WebSocket 简介二、WebSocket 特点三、为什么需要 WebSocket四、WebSocket 连接流程五、WebSocket 使用场景六、使用案例1.提醒客户端有新订单2.客户端交互一、WebSocket 简介 WebSocket 是一种基于 TCP…

为什么越来越多的企业在会议室使用无线流媒体网关?

1&#xff0c;用户已有华为&#xff0c;MAXHUB等投屏功能设备&#xff0c;不需要这个设备了。但是市面上大部分投屏设备的使用存在以下问题&#xff1a; 操作麻烦&#xff0c;我们发射器是直接触摸投屏&#xff0c;安全性低&#xff0c;需要驱动软件。 2&#xff0c;市场上有很…

实现矩阵连乘积(动态规划)

目录 实现矩阵连乘积 题目 问题分析 算法分析 时间复杂度 代码实现 执行结果 动态规划 基本思想 举例 个人主页&#xff1a;天寒雨落的博客_CSDN博客-初学者入门C语言,python,数据库领域博主 &#x1f4ac; 热门专栏&#xff1a;初学者入门C语言_天寒雨落的博客-CSDN…

【SVM分类】基于鸽群算法优化支持向量机SVM实现分类附matlab的代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

arduino 复习题

名词解释 中断 计算机运行过程中&#xff0c;出现某些意外情况需主机干预时&#xff0c;机器能自动停止正在运行的程序并转入处理新情况的程序&#xff0c;处理完毕后又返回原被暂停的程序继续运行 中断服务程序 用于 CPU 处理中断的程序 中断源 引起中断的原因&#xff0c;或…

【JVS低代码平台】如何实现与外部系统/内部代码直接对接?

JVS是开放性的低代码开发平台&#xff0c;为开发团队预留了多种对接的方式。我这里列举集中对接的模式。 用户对接&#xff08;统一登录/单点跳转&#xff09; 在日常的企业需求中&#xff0c;常常有这种情况。企业内部考勤打开都是通过钉钉或者企微的&#xff0c;那么希望我们…

Grasp Detection论文、代码汇总

文章目录2022End-to-end Trainable Deep Neural Network for Robotic Grasp Detection and Semantic Segmentation from RGB2019Antipodal Robotic Grasping using Generative Residual Convolutional Neural Network2022 End-to-end Trainable Deep Neural Network for Robot…

现代PCB生产工艺——加成法、减成法与半加成法

继续为朋友们分享关于PCB生产工艺的知识。 现代PCB生产工艺&#xff0c;目前主要分为&#xff1a;加成法、减成法与半加成法。 其具体定义如下&#xff1a; 加成法&#xff1a; 通过网印或曝光形成图形&#xff0c;经钻孔、沉铜、转移层压等工艺加工&#xff0c;直接将导电图形…

Pycharm开发环境下创建python运行的虚拟环境(自动执行安装依赖包)

问题&#xff1a;基于Django开发的后台程序涉及到很多依赖的开发包&#xff0c;将该项目迁移到其它电脑环境下运行需要搭建环境&#xff0c;由于项目中有requirement.txt&#xff0c;该文件内包含了运行该项目所需的依赖&#xff1b;最简便的方式是执行命令自动安装requirement…

postgresql11 主从配置详解

以下内容是针对pgsql11来做的。请看好版本再去考虑是否往下看 准备两台服务器&#xff0c;地址如下&#xff1a; 主&#xff1a;192.168.0.1pgsql11从:192.168.0.2pgsql11一、主库配置 1、创建具有复制权限的用户replica 密码为000000 CREATE ROLE replica login replicat…

Docker——数据卷命令

目录 一、数据卷 1.1 便于修改 1.2 数据共享 1.3 安全问题 1.4 数据卷的基本语法 二、 创建数据卷&#xff0c;并查看数据卷在宿主机的目录位置 2.1 创建数据卷 2.2 查看所有数据卷 2.3 查看数据卷详细信息卷 2.4 删除数据卷 三、挂载数据卷 3.1 创建容器并挂载数据卷…

智慧国土解决方案-最新全套文件

智慧国土解决方案-最新全套文件一、建设背景二、建设思路1、紧盯三大领域2、划分三个阶段3、面向三个维度三、建设方案轻应用微服务大平台应用设计四、获取 - 智慧国土全套最新解决方案合集一、建设背景 2019年5月9日&#xff0c;印发《关于建立国土空间规划体系并监督实施的若…

Pandas 数据中的loc与iloc含义以及操作

本节学习并记录pandas 的DataFrame类型的数据是怎么对列或者行进行操作的 1、df.loc: 语法格式是df.loc[<行表达式>, <列表达式>]&#xff0c;如果列不传将返回所有的行&#xff0c;loc操作通过索引和列的条件筛选出数据。 2、df.iloc: 语法格式是df.iloc[<行…

python初级学习

第一章 为什么要学习Python 那些最好的程序员不是为了得到更高的薪水或者得到公众的仰慕而编程,他们只是觉得这是-件有 趣的事情。 ——Linux 之父 Linus TorvaIds 作为-个实用主义的学习者,最关心的问题-定是「我为什么要选择学 Python, 学会之后我可以用来做什么&#xff1…

基于springboot电动车智能充电服务平台设计与实现的源码+文档

摘 要 在Internet高速发展的今天&#xff0c;我们生活的各个领域都涉及到计算机的应用&#xff0c;其中包括电动车智能充电服务平台的网络应用&#xff0c;在外国电动车智能充电服务平台已经是很普遍的方式&#xff0c;不过国内的电动车智能充电服务平台可能还处于起步阶段。电…

Briefings in bioinformatics2022 | 基于神经网络的分子性质预测通用优化策略

原文标题&#xff1a;A general optimization protocol for molecular property prediction using a deep learning network 代码&#xff1a;GitHub - titanda/Learn-it-all at ready_classification_feature 一、问题提出 虽然个别优化方法都成功地提高了模型的性能&#…

2022年IT服务行业研究报告

第一章 行业概况 IT服务是指在信息技术领域服务商为其用户提供信息咨询、软件升级、硬件维修等全方位的服务。IT服务产品包括&#xff1a;硬件集成、软件集成、通用解决方案、行业解决方案和IT综合服务。 服务过程是指IT需求得以满足的全过程&#xff0c;从IT服务商为用户提供…