动态规划之矩阵连乘

Posted AI小白奋斗史

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划之矩阵连乘相关的知识,希望对你有一定的参考价值。

零.描述

题目:给定n个矩阵{A0,A1,A2, …, An-1},其中Ai,i=0, …, n-1的维数为 pi*pi+1,并且 Ai和 Ai+1是可乘的。考察这 n 个矩阵的连乘积 A0A1A2…An-1,由于矩阵乘法满足结合律,所以计算矩阵的连乘可以有多种不同的计算次序。结合动态规划思想,编程确定 n 个矩阵的连乘次序,使得按照这个次数计算矩阵连乘,需要的“数乘”次数最少。


Input:输入矩阵个数 n,以及每一个矩阵的尺寸;

Output:输出最佳矩阵连乘次序和数乘次数;


比如

A0[20*25],A1[25*15],A2[15*5],A3[5*12]

则结果可能有以下情况

(A0A1)(A2A3)、((A0(A1A2))A3)、A0((A1A2)A3)...

我们需要得到计算效率最优的括号方式



二.算法:动态规划

原问题为n个矩阵连乘,利用动态规划的思想将原问题分解为子问题,

(1) n==1时,单一矩阵,不需要计算,最小数乘次数为0;

(2) n==2时,根据n==1时的结果,遍历计算出每相邻两个矩阵的最小乘次;

(3) n==3时,根据n==1和n==2时的结果,此时已经求出每相邻1个,2个矩阵的最小乘次,遍历计算出该相邻三个矩阵的最小乘次;


以此类推,当n==k时,根据n==1,n==2,n==k-1时的结果,此时已经求出每相邻1个,2个,3个......k-1个矩阵的最小乘次。每当n增加1时,就利用已求出的子结构来求解此时的最优解。


动态规划步骤:

(1) 定义子问题。DP[i,j]表示从第i个矩阵到第j个矩阵,可通过DP得到优化解。

(2) 建立子问题之间的关系。

设矩阵Ai的维数为Pi*Pi+1,DP[i,j]表示得到Ai,j的最小相乘次数,递推方程如下:

动态规划之矩阵连乘

(3) 确定边界条件。当i=j,只有一个矩阵,DP[i,j]=0

(4) 得到原问题的解

对于具体例子

A = [20*25,25*15,15*5,5*12],按照递推方程可以得到以下结果

注意:计算顺序为先计算红色区域,再计算蓝色区域,最后计算黄色区域。分别代表两个矩阵连乘、三个矩阵连乘和四个矩阵连乘。



三.编程实现

import numpy as np

def matrixChain(p, n=1, memo=None, seq=None):
    size = len(p) - n  # 子问题个数
    if n == 1:  # 长度为1的矩阵链,数乘次数为0
        memo = np.zeros([size, size], dtype=int)
        seq = np.zeros([size, size], dtype=int)
    else:
        for i in range(size):  # 左边界
            j = i + n - 1  # 右边界
            for k in range(i, j):  # 分界位置
                t = memo[i, k] + memo[k + 1, j] + p[i] * p[k + 1] * p[j + 1]
                if t < memo[i, j] or memo[i, j] == 0:
                    memo[i, j] = t
                    seq[i, j] = k
    if n < len(p) - 1:
        matrixChain(p, n + 1, memo, seq)
    return memo, seq


def prtSeq(seq, i, j):
    size = j - i + 1
    if size == 1:
        return 'A%d' % i  # A1,A2..
    else:
        k = seq[i, j]  # 分界位置
        res = ''
        res += '(' + prtSeq(seq, i, k)
        res += prtSeq(seq, k + 1, j) + ')'
        return res


if __name__ == '__main__':
    n = eval(input('请输入矩阵个数:'))  # 4
    p = eval(input('请输入矩阵尺寸:'))  # 20,25,15,5,12
    m, seq = matrixChain(p)
    res = prtSeq(seq, 0, n - 1)
    print('最佳数乘次序:%s, 此时数乘次数:%d' % (res[1:-1], m[0-1]))
    # 最佳数乘次序:(A0(A1A2))A3, 此时数乘次数:5575


END

往期回顾

以上是关于动态规划之矩阵连乘的主要内容,如果未能解决你的问题,请参考以下文章

动态规划之矩阵连乘

动态规划之矩阵连乘

动态规划之矩阵连乘

矩阵连乘最优解---动态规划

动态规划:矩阵连乘问题

矩阵连乘问题(动态规划算法)