zoukankan      html  css  js  c++  java
  • python动态规划解决矩阵连乘

    矩阵连乘:给定n个矩阵:A1,A2,...,An,其中Ai与Ai+1是可乘的,i=1,2...,n-1。确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。输入数据为矩阵个数和每个矩阵规模,输出结果为计算矩阵连乘积的计算次序和最少数乘次数。

    若A是一个p*q的矩阵,B是一个q*r的矩阵,则其乘积C=AB是一个p*r的矩阵。数乘次数是p*q*r.

    动态规划算法与分治法类似,其基本思想也就是将待求解的问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解,简单概括为自顶向下分解,自底向上求解。与分治法不同的是,适合于用动态规划法求解的问题,经分解得到的子问题往往不是相互独立的,换句话说,就是前面解决过的子问题,在后面的子问题中又碰到了前面解决过的子问题,子问题之间是有联系的。如果用分治法,有些同样的子问题会被重复计算几次,这样就很浪费时间了。所以动态规划是为了解决分治法的弊端而提出的,动态规划的基本思想就是,用一个表来记录所有已经解决过的子问题的答案,不管该子问题在以后是否会被用到,只要它被计算过,就将其结果填入表中,以后碰到同样的子问题,就可以从表中直接调用该子问题的答案,而不需要再计算一次。具体的动态规划的算法多种多样,但他们都具有相同的填表式。

       顺便说一下动态规划的适用场合,一般适用于解最优化问题,例如矩阵连乘问题、最长公共子序列、背包问题等等,通常动态规划的设计有4个步骤,结合矩阵连乘分析:

    (1).找出最优解的性质,并刻画其结构特征

        这是设计动态规划算法的第一步,我们可以将矩阵连乘积AiAi+1……Aj记为A[i:j]。问题就是计算A[1:n]的最优计算次序。设这个计算次序在矩阵Ak和Ak+1之间将矩阵链断开,1<=k<n,使其完全加括号方式为((A1……Ak)(AK+1……An)),这样就将原问题分解为两个子问题,,按此计算次序,计算A[1:n]的计算量就等于计算A[1:k]的计算量加上A[k+1:n]的计算量,再加上A[1:k]和A[k+1:n]相乘的计算量。计算A[1:n]的最优次序包含了计算A[1:k]和A[k+1:n]这两个子问题的最优计算次序,以此类推,将A[1:k]和A[k+1:n]递归的分解下去,求出每个子问题的最优解,子问题的最优解相乘便得到原问题的最优解。

       (2).递归地定义最优值

               这是动态规划的第二步,对于矩阵连乘积的最优计算次序的问题,设计算A[i:j],1<=i<=j<=n,所需要的最小数乘次数为m[i][j],则原问题的最优值为m[1][n]。

               当i=j时,A[i:j]=Ai为单一的矩阵,则无需计算,所以m[i][j]=0,i=j=1,2,……,n。即对应的二维表对角线上的值全为0。

               当i<j时,这就需要用步骤(1)的最优子结构性质来计算m[i][j]。若计算A[i:j]的最优次序在Ak和Ak+1之间断开,i<=k<j,则m[i][j]=m[i][k]+m[k+1][j]+pi-1*pk*pj,k的位置只有j-i种可能,即k属于集合{i,i+1,……,j-1},所以k是这j-i个位置中使计算量达到最小的那个位置。

              所以m[i][j]可以递归地定义为        m[i][j]={  0                                                            i=j

                                                                          min{m[i][k]+m[k+1][j]+pi-1*pk*pj }         i<j ,i<=k<j     }

             将对应于m[i][j]的断开位置k记为s[i][j],在计算出最优值m[i][j]后,可递归地由s[i][j]构造出相应的最优解

       (3).以自底向上的方式计算出最优值

              动态规划的一大好处是,在计算的过程中,将已解决的子问题答案保存起来,每个子问题只计算一次,而后面的子问题需要用到前面已经解决的子问题,就可以从表中简单差出来,从而避免了大量的重复计算

    import random
    from pandas import *
    
    input = int(input("输入矩阵数:"))
    matrix = [[0] * 2 for i in range(input)]
    for i in range(input):                         #生成矩阵
        if i == 0:
            matrix[i][0] = random.randrange(100)
            matrix[i][1] = random.randrange(100)
        else:
            matrix[i][0] = matrix[i-1][1]
            matrix[i][1] = random.randrange(100)
    m = [[0] * input for i in range(input)]         #记录连乘次数
    s = [[0] * input for j in range(input)]         #记录括号位置
    def MatrixMultiplication(inp):
        for i in range(inp):
            m[i][i] = 0
        for r in range(1, inp):
            for i in range(inp-r):
                j = i + r
                m[i][j] = m[i+1][j] + matrix[i][0] * matrix[i][1] * matrix[j][1]
                s[i][j] = i+1
                for k in range(i+1, j):
                    judge = m[i][k] + m[k+1][j] + matrix[i][0] * matrix[k][1] * matrix[j][1]
                    if judge < m[i][j]:
                        m[i][j] = judge
                        s[i][j] = k+1
    def printmatrix(left, right):
        if left == right:
            print("A"+str(left+1), end='')
        else:
            print("(", end='')
            printmatrix(left, s[left][right]-1)
            printmatrix(s[left][right], right)
            print(")", end='')
    MatrixMultiplication(input)
    dm = DataFrame(m, index=list(range(1, input+1)), columns=list(range(1, input+1)))
    ds = DataFrame(s, index=list(range(1, input+1)), columns=list(range(1, input+1)))
    print(matrix)
    print("数乘次数:
    ", dm)
    print("括号位置:
    ", ds)
    print("最终结果:")
    printmatrix(0, input-1)
    

      

  • 相关阅读:
    什么是马甲APP?怎么用马甲APP导流
    OC与JS交互前言-b
    UIWebView1-b
    Mac双系统切换
    iOS之手势滑动返回功能
    Duplicate Symbol链接错的原因总结和解决方法-b
    #ifndef#define#endif的用法-b
    iOS Copy 和 MutableCopy的区别 深浅拷贝的区别-供参考
    解决CocoaPods在OS X 10.11出现问题-b
    django中cookies和session
  • 原文地址:https://www.cnblogs.com/whitehawk/p/10887702.html
Copyright © 2011-2022 走看看