• 『动态规划』矩阵连乘


    活动地址:CSDN21天学习挑战赛
    👨‍🎓作者简介:一位喜欢写作,计科专业大三菜鸟

    🏡个人主页:starry陆离

    🕒首发日期:2022年8月16日星期二

    🌌上期文章:『动态规划』动态规划概述

    📚订阅专栏:『算法分析与设计』
    如果文章有帮到你的话记得点赞👍+收藏💗支持一下哦

    在这里插入图片描述

    1.完全加括号的矩阵连乘积

    完全加括号的矩阵连乘积可递归地定义为:

    • 单个矩阵是完全加括号的
    • 矩阵连乘积A是完全加括号的,则A可表示为2个完全加括号的矩阵连乘积B和C 的乘积并加括号,即A=(BC)

    设有四个矩阵A, B, C, D ,它们的维数分别是:

    A = 50*10 B = 10*40 C = 40*30 D = 30*5

    总共有五种完全加括号的方式:

    image-20220502105237071

    2.矩阵连乘问题

    • 给定n个矩阵{A1,A2,…,An},其中Ai和Ai+1是可乘的,i=1,2,…,n-1

    • 考察n个矩阵的连乘积

      A1 A2 … An

    • 矩阵乘法满足结合律->计算矩阵的连乘可以有许多不同的计算次序->计算次 序可以用加括号的方式来确定

    • 若一个矩阵连乘积的计算次序完全确定(该连乘积已完全加括号)->可依此 次序反复调用2个矩阵相乘的标准算法计算出矩阵连乘积

    问?? 如何确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的 数乘次数最少

    2.2穷举法

    列举出所有可能的计算次序,并计算出每一种计算次序相应需要的数乘 次数,从中找出一种数乘次数最少的计算次序

    算法复杂度分析: 对于n个矩阵的连乘积,设其不同的计算次序为P(n)。 由于每种加括号方式都可以分解为两个子矩阵的加括号问题:

    (A1 ...Ak )(Ak+1…An )可以得到关于P(n)的递推式如下:

    image-20220502110159702

    2.3动态规划

    2.3.1问题分析

    将矩阵连乘积 AiAi+1......Aj,简记为A[i:j],i≤j

    考察计算A[i:j]的最优计算次序:设这个计算次序在矩阵AkAk+1之间将矩阵 链断开,i≤k,则其相应完全加括号方式为

    image-20220502110537945

    计算量:A[i:k]的计算量加上A[k+1:j]的计算量,再加上A[i:k]和A[k+1:j]相 乘的计算量(三部分组成)

    2.3.2分析最优解的结构

    特征:计算A[i:j]的最优次序所包含的计算矩阵子链A[i:k]A[k+1:j]的次序也是也是最优的

    矩阵连乘计算次序问题的最优解包含着其子问题的最优解->因此具备最优子结构

    image-20220502110844900

    2.3.3建立递归关系

    计算A[i:j],1≤i≤j≤n,所需要的最少数乘次数m[i,j],则原问题的最优值为 m[1,n]

    • i=j时,A[i:j]=Ai,因此,m[i,i]=0,i=1,2,…,n
    • i时,m[i,j]=m[i,k]+m[k+1,j]+ Pi-1 · Pk · Pj

    Ai的维数为Pi-1 · Pi

    可以递归地定义m[i,j]为:

    image-20220502111535795

    2.3.4计算最优值

    对于1≤i≤j≤n不同的有序对(i,j)对应于不同的子问题。不同子问题的个数最多只 有:O(n^2)

    在递归计算时,许多子问题被重复计算多次->重叠子问题

    • 用动态规划算法解此问题,可依据其递归式以自底向上的方式进行计算,在计算过程中,保存已解决的子问题答案
    • 每个子问题只计算一次,而在后面需要时只要简单查一下,从而避免大量的重 复计算,最终得到多项式时间的算法

    image-20220502215120000

    2.3.5用动态规划求解最优解

    image-20220502215220271

    3.算法实现

    3.1备忘录法

    /*
    int n;//输入的数的个数
    int[] num;//储存数
    int[][] m;//动态规划数组,保存当前最优解
    int[][] s;//用于构造最优解
    */
    
    import java.util.Scanner;
     
    public class Main {
        public static void main(String[] args) {
            Scanner scanner=new Scanner(System.in);
            int n;
            int[] num;
            int[][] m;
            int[][] s;
            while(scanner.hasNext()) {
                n=scanner.nextInt();
                num=new int[n];
                m=new int[n][n];
                p=new int[n];
                s=new int[n][n];
                for(int i=0;i<n;++i) {
                    num[i]=scanner.nextInt();
                }
                int ans=Solve(1,n-1,m,num,s);
                System.out.println(ans);
            }
        }
        private static int Solve(int i, int j,int[][] m,int[] num,int[][] s) {
            if(m[i][j]>0)return m[i][j];                      
            if(i==j)return 0;
            int u=Solve(i+1, j, m,num,s)+num[i-1]*num[i]*num[j];
            s[i][j]=i;
            for(int k=i+1;k<j;++k) {
                int t=Solve(i, k, m, num, s)+Solve(k+1, j, m, num, s)+num[i-1]*num[k]*num[j];
                if(t<u) {
                    u=t;s[i][j]=k;
                }
                m[i][j]=u;
            }
            return u;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    3.2动态规划

    import java.util.Scanner;
     
    public class Main {
     
        public static void main(String[] args) {
            Scanner scanner=new Scanner(System.in);
            int n;
            int[] num;
            int[][] m;
            int[][] s;
            while(scanner.hasNext()) {
                n=scanner.nextInt();
                num=new int[n+1];
                m=new int[n+1][n+1];
                s=new int[n+1][n+1];
                for(int i=0;i<n;++i) {
                    num[i]=scanner.nextInt();
                }
                n=n-1;
                for(int i=1;i<=n;++i) {m[i][i]=0;}
                for(int r=2;r<=n;r++) {
                    for(int i=1;i<=n-r+1;i++) {
                        int j=i+r-1;
                        m[i][j]=m[i+1][j]+num[i-1]*num[i]*num[j];
                        s[i][j]=i;
                        for(int k=i+1;k<j;k++) {
                            int t=m[i][k]+m[k+1][j]+num[i-1]*num[k]*num[j];
                            if(t<m[i][j]) {
                                m[i][j]=t;
                                s[i][j]=k;
                            }
                        }
                    }
                }
                traceback(s,1,n);
                //System.out.println(m[1][n]);
            }
        }
     
        private static void traceback(int[][] s, int i, int j) {
            if(i==j)return;
            traceback(s, i, s[i][j]);
            traceback(s, s[i][j]+1, j);
            System.out.println("A["+i+":"+s[i][j]+"] * A["+(s[i][j]+1)+":"+j+"]");
             
        }
     
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
  • 相关阅读:
    计网学习笔记三 MAC与LAN
    【车辆动力】基于matlab模拟停车动力学【含Matlab源码 2258期】
    正厚干货 | 软件测试面试题库
    【golang】go 返回参数 以及go中 裸返
    Java线程池
    C# 删除文件夹
    python练习题(markdown中的60道题)
    【论文阅读|深读】DRNE:Deep Recursive Network Embedding with Regular Equivalence
    Java.lang.Class类 getProtectionDomain()方法有什么功能呢?
    spark sql重分区
  • 原文地址:https://blog.csdn.net/weixin_53463734/article/details/126355970