IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 矩阵连乘(动态规划) -> 正文阅读

[数据结构与算法]矩阵连乘(动态规划)

问题描述

给定N 个矩阵 { A 1 , A 2 , A 3 … … A n } ,其中 A i 和 A i + 1 可以相乘的,即: A i
的列数等于 A i + 1行数。如何确定矩阵连乘的计算次序,使得按照此次序计算该矩阵连乘所需要的数乘次数最少?
两个矩阵相乘,它的数乘次数等于前一个矩阵的行数乘以后一个矩阵的列数,当这些矩阵相乘的次序不同时,它的数乘次数的有很大差异的。
输入A = [30, 35, 15, 5, 10, 20, 25],表示6个矩阵在这里插入图片描述
输出最优的数乘次数与最佳分隔位置:最优的数乘次数15125 ; 最佳分隔位置 [3, 1, 5] (分隔点之间的顺序任意)。

如下例题:
例:现有四个矩阵 A , B , C , D 他们的维数分别是:A = 50 ? 10 , B = 10 ? 40 , C = 40 ?
30 , D = 30 ? 5 ,则连乘 A , B , C , D 共有五种相乘的次序,如:

( A ( ( B C ) D ) ) ,数乘次数为 16000
( ( A B ) ( C D ) ),数乘次数为 36000
( ( A ( B C ) ) D ) ,数乘次数为 34500
( A ( B ( C D ) ) ) ,数乘次数为 10500
( ( ( A B ) C ) D ) ,数乘次数为 87500
我们可以看到,连乘的次序不同,它的数乘次数大区别也是很大的,最少的 10500
次,最多的,87500 次,相差 8 倍之多。所以,寻找一个矩阵连乘的最优分隔方式就显得尤为重要。

使用动态规划解决该问题的思路:

f [ i , j ] f[i,j] f[i,j]为矩阵从Ai连乘到Aj的最优数乘值,因此可以写出如下递推公式:
在这里插入图片描述
设定一个二维数组m[N][N]表示当前矩阵的连乘次数,比如m[i][j]表示矩阵从Ai连乘到Aj的最优数乘值f[i,j]。
再设定一个二维数组s[N][N]表示当前矩阵连乘时最优分隔位置,比如s[i][j]表示矩阵从Ai连乘到Aj的数乘值最小时的分隔位置,也就是加括号的位置。

接下来画表:
连乘矩阵 :{ A 1 , A 2 , A 3 , A 4 , A 5 , A 6 }
在这里插入图片描述
m数组(状态转移矩阵):
在这里插入图片描述

  • 在计算该列表中的数据时,我首先可以明确对角线的值即f[i,i]都为0,因为这表示只有一个矩阵,数乘为0
  • 然后我们首先比较容易计算的就是两个矩阵相乘的最优数乘次数,因为两个矩阵相乘,分隔点只有一个,此时对应于主对角线的相邻对角线的值,即m[1,2], m[2,3], m[3,4], m[4,5], m[5,6]。当这几个值计算得到后,我们就可以接着计算三个矩阵相乘的最优数乘值,也就是m[1,3], m[2, 4], m[3, 5], m[4, 6],例如m[1,3]的分隔点有两个,分别是1和2,当分隔点k为1时:f[1,1]+f[2,3]+a0 * a[1] * a[3],当分隔点k为2时:f[1][2]+f[2][3]+a0 * a2 * a3,而m[1,3]取二者的最小值作为最优数乘值。依次类推,因此状态转移是从主对角线依次计算对角线,最终m[1,6]即为所求值。
  • 需要注意,m数组是索引为1的行和列来记录状态的,索引为0的行和列不用,这样做主要为了便去实现上面的推理。
    s数组:
    在这里插入图片描述
    对于输出最优分隔位置,根据上图可以看出s[1,6]=3,首先在3处分隔,此时变为s[1,3]与s[4,6],s[1,3]在1处分隔,变为s[1,1]与s[2,3],s[4,6]在5处分隔,变为s[4,5]与s[6,6]。所以在1,3,5处分隔。因此可以利用递归完成。

完整代码:


def getIndex(i, j, s):
    global index
    if j - i >= 2:
        index.append(s[i][j])
    else:
        return
    getIndex(i, s[i][j], s)
    getIndex(s[i][j] + 1, j, s)


def matrixChain(a):
    n = len(a)
    m = [[0 for _ in range(n)] for _ in range(n)]
    s = [[0 for _ in range(n)] for _ in range(n)]

    for r in range(2, n):  # r个矩阵连乘
        for i in range(1, n - r + 1):  # 填补表格的斜线部分的元素对应i标
            j = i + r - 1  # 填补表格的斜线部分的元素对应的j标
            m[i][j] = m[i][i] + m[i + 1][j] + a[i - 1] * a[i] * a[j]  # 首先计算第一个分割点,例如[1,3]的第一个分割点为1
            s[i][j] = i  # 然后将分割点暂时记录
            for k in range(i + 1, j):  # 计算其他的分隔点的数乘次数
                temp = m[i][k] + m[k + 1][j] + a[i - 1] * a[k] * a[j]
                if temp < m[i][j]:  # 如果当前分隔点的数乘次数更优,则更新
                    s[i][j] = k
                    m[i][j] = temp
    getIndex(1, n-1, s)  # 计算分隔点的位置

    return m[1][-1], index


if __name__ == "__main__":
    A = [30, 35, 15, 5, 10, 20, 25]
    index = []
    result = matrixChain(A)
    print(result)

在这里插入图片描述

参考:
https://blog.csdn.net/weixin_44952817/article/details/110124596
https://blog.csdn.net/qq_44755403/article/details/105015330

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-03-03 16:39:43  更:2022-03-03 16:43:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 15:34:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码