zoukankan      html  css  js  c++  java
  • 矩阵链相乘

    问题描述

    给定若干个矩阵,寻找最优的相乘次序,使得乘法运算的次数最少,并输出对应的最少运算次数。比如现有三个矩阵ABC,维数分别为A:2×10B:10×2, C:2×10 。虽然(AB)C=A(BC) 结果是相等的,即与相乘次序没有关系。但是(AB)C乘法运算的次数为2×10×2+2×2×10=802×10×2+2×2×10=80,而A(BC)为10×2×10+2×10×10=40010×2×10+2×10×10=400,显然(AB)C的运算次数更少,即效率更高。

    思路

    求解的关键在于如何将问题分解为若干子问题。我们想象在各个矩阵之间可以放上隔板,那么只要先分别求解左和右的最少乘法次数,再将隔板左右的两部分相乘,就可以得到当前分隔方法的最优解,最后通过比较各种分隔方法,就能得到当前长度的最优解,如下图中四种分隔中我们取最少的次数,即为长度5(5个连续矩阵)的最优解。由于分隔后的长度必定小于当前长度,如此处的子问题长度必定小于5,而子问题已经在之前的迭代过程求得,无需重复计算。通过下一部分的迭代过程展示能有更直观的理解。

    思路1:递归,把原数组从i到j-1做切分,计算切分之后两个子序列连乘的乘积之和和两个子序列总体的乘积

    时间复杂度指数级,会有重复计算

    代码如下:

    #递归
    def MatrixChainOrder(p,i,j):
        if i == j:
            return 0
        mins = 2 ** 32
    
        k = i
        while k < j:
            #count分成三份,从k做切分,[i,k]+[k+1,j]+总体
            count = MatrixChainOrder(p,k+1,j) + MatrixChainOrder(p,i,k) + p[i-1] * p[k] * p[j]
            #p[i-1] * p[k] * p[j]是两个子序列连乘的乘积矩阵再相乘的计算量
            print(i,k,j,count)
    
            if count < mins:
                mins = count
            k += 1
        return mins

    思路2:动态规划

    自下而上的方式构造临时数组来保存子问题的中间结果,避免重复计算

    时间复杂度O(N^3),空间复杂度O(N^2)

    迭代过程:

    为了更直观的理解,下图和上面是等效的。(符号说明:m[a,b]代表从序号为a到序号为b的矩阵链所需的最少乘法次数,特别地,m[a,a]代表a号矩阵本身,很明显m[a,a]=0。)

    先计算第二行(m[1,2],m[2,3],m[3,4],m[4,5]),然后第三行(m[1,3],m[2,4],m[3,5]),....

     

    算法实现

    arr[]数组用于记录矩阵链信息,其中n号矩阵对应的维数是arr[n-1]*arr[n]。动态规划的核心算法利用3个for循环,最外层控制矩阵链长度,下一层控制起始点,再下一层控制隔板的位置。最后左右合并的时候注意下标的选择,如下图所示。

    代码如下:

    #动态规划,自下而上
    def MatrixChainOrder2(p,n):
        cost = [([None]*n) for i in range(n)]
        i = 1
        while i < n:
            cost[i][i] = 0
            i += 1
        cLen = 2
        #i=start,j=end,cLen=length
        while cLen < n:
            i = 1
            while i < n-cLen+1:
                j = i + cLen - 1
                print(i,j,cLen)
                cost[i][j] = 2 ** 31
                k = i
                while k <= j-1:
                    q = cost[i][k] + cost[k+1][j] + p[i-1]*p[k]*p[j]
                    if q < cost[i][j]:
                        cost[i][j] = q
                    k += 1
                i += 1
            cLen += 1
        # print(cost)
        return cost[1][n-1]

     结果如下:

    1 2 2
    2 3 2
    3 4 2
    4 5 2
    1 3 3
    2 4 3
    3 5 3
    1 4 4
    2 5 4
    1 5 5
    res 11875

  • 相关阅读:
    Oracle连接数一直在增
    ora00020: maximum number of processes (150) exeeded
    oracle归档日志满了
    C# ZPL
    error CS0227: 不安全代码只会在使用 /unsafe 编译的情况下出现
    最全zpl语言指令解析(含乱码)
    ZPL 打印机实例
    ora-01400 无法将NULL插入 ID 解决方法
    windows 选择时间控件(选择日期, 小时分钟秒)
    用户登陆检验----没有优化,大神可以帮忙优化优化
  • 原文地址:https://www.cnblogs.com/nxf-rabbit75/p/10450009.html
Copyright © 2011-2022 走看看