• 动态规划—矩阵链乘法


    矩阵链乘问题描述

    给定n个矩阵构成的一个链<A1,A2,A3,.......An>,其中i=1,2,...n,矩阵A的维数为pi-1pi,对乘积 A1A2...A以一种最小化标量乘法次数的方式进行加全部括号。

    注意:在矩阵链乘问题中,实际上并没有把矩阵相乘,目的是确定一个具有最小代价的矩阵相乘顺序。找出这样一个结合顺序使得相乘的代价最低。

    动态规划分析过程

    1)最优加全部括号的结构

      动态规划第一步是寻找一个最优的子结构。假设现在要计算AiAi+1....Aj的值,计算Ai...j过程当中肯定会存在某个k值(i<=k<j)将Ai...j分成两部分,使得Ai...j的计算量最小。分成两个子问题Ai...k和Ak+1...j,需要继续递归寻找这两个子问题的最优解。

      有分析可以到最优子结构为:假设AiAi+1....Aj的一个最优加全括号把乘积在Ak和Ak+1之间分开,则Ai..k和Ak+1..j也都是最优加全括号的。

    2)一个递归解

      设m[i,j]为计算机矩阵Ai...j所需的标量乘法运算次数的最小值,对此计算A1..n的最小代价就是m[1,n]。现在需要来递归定义m[i,j],分两种情况进行讨论如下:

    当i==j时:m[i,j] = 0,(此时只包含一个矩阵)

    当i<j 时:从步骤1中需要寻找一个k(i≤k<j)值,使得m[i,j] =min{m[i,k]+m[k+1,j]+pi-1pkpj} (i≤k<j)。

    3)计算最优代价

      虽然给出了递归解的过程,但是在实现的时候不采用递归实现,而是借助辅助空间,使用自底向上的表格进行实现。设矩阵Ai的维数为pi-1pi,i=1,2.....n。输入序列为:p=<p0,p1,...pn>,length[p] = n+1。使用m[n][n]保存m[i,j]的代价,s[n][n]保存计算m[i,j]时取得最优代价处k的值,最后可以用s中的记录构造一个最优解。书中给出了计算过程的伪代码,摘录如下:

    MAXTRIX_CHAIN_ORDER(p)
     2   n = length[p]-1;
     3   for i=1 to n
     4       do m[i][i] = 0;
     5   for t = 2 to n  //t is the chain length
     6        do for i=1 to n-t+1
     7                      j=i+t-1;
     8                      m[i][j] = MAXLIMIT;
     9                      for k=i to j-1
    10                             q = m[i][k] + m[k+1][i] + qi-1qkqj;
    11                             if q < m[i][j]
    12                                then m[i][j] = q;
    13                                     s[i][j] = k;
    14   return m and s;

    MATRIX_CHAIN_ORDER具有循环嵌套,深度为3层,运行时间为O(n3)。如果采用递归进行实现,则需要指数级时间Ω(2n),因为中间有些重复计算。

    4)构造一个最优解

    第三步中已经计算出来最小代价,并保存了相关的记录信息。因此只需对s表格进行递归调用展开既可以得到一个最优解。书中给出了伪代码,摘录如下:

    PRINT_OPTIMAL_PARENS(s,i,j)
       if i== j 
          then print "Ai"
       else
          print "(";
          PRINT_OPTIMAL_PARENS(s,i,s[i][j]);
          PRINT_OPTIMAL_PARENS(s,s[i][j]+1,j);
          print")";

    5)编程实现

    public class Q1_Matrix_chain {
        public static int[] atest ={30,35,15,5,10,20,25};
        public static int[] a={3, 5, 2, 1, 10};
        public static int[] b={2, 7, 3, 6, 10};
        public static int[] c={10, 3, 15, 12, 7, 2};
        public static int[] d={7, 2, 4, 15, 20, 5};
        public static void main(String[] args)
        {
            System.out.println("<3, 5, 2, 1,10>");
            Matrix_Chain_Order(a);
            System.out.println("<2, 7, 3, 6, 10>");
            Matrix_Chain_Order(b);
            System.out.println("<10, 3, 15, 12, 7, 2>");
            Matrix_Chain_Order(c);
            System.out.println("<7, 2, 4, 15, 20, 5>");
            Matrix_Chain_Order(d);
    
        }
    
        public static void Matrix_Chain_Order(int[] a){
            int n = a.length-1;
            int[][] m = new int[n+1][n+1];
            int[][] s = new int[n+1][n+1];
            int i,j,k,t;
    
            for (i=0;i<=n;i++)
                m[i][i] = 0;
            for (i=0;i<=n;i++)
                s[i][i] = 0;
            for(t=2; t<=n; t++) //t is the chain length
            {
                for(i=1;i<=n-t+1;i++)//从第一矩阵开始计算,计算长度为t的最小代价
                {
                    j = i+t-1;//长度为t时候的最后一个元素
                    m[i][j] = 1000000;//初始化为最大代价
                    for(k=i;k<=j-1;k++)//寻找最优的k值,使得分成两部分k在i与j-1之间
                    {
                        int temp = m[i][k]+m[k+1][j] + a[i-1]*a[k]*a[j];
                        if(temp < m[i][j])
                        {
                        m[i][j] = temp;   //记录下当前的最小代价
                        s[i][j] = k;      //记录当前的括号位置,即矩阵的编号
                        }
                    }
                }
            }
            System.out.println("一个最优解为:");
            Display(s,1,n);
            System.out.println("
    计算的次数为:");
            System.out.println(m[1][n]);
        }
        public static void Display(int[][] s,int i,int j)
        {
            if( i == j)
            {
                System.out.print('A');
                System.out.print(i);
            }
            else
            {
                System.out.print('(');
                Display(s,i,s[i][j]);
                Display(s,s[i][j]+1,j);
                System.out.print(')');
            }
    
        }
    
    }

     

  • 相关阅读:
    Java8 Time
    Java8 Stream
    Java8 Lambda
    Thinking in java 阅读
    String 中的 split 进行字符串分割
    Kubernetes 学习(九)Kubernetes 源码阅读之正式篇------核心组件之 Scheduler
    Kubernetes 学习(八)Kubernetes 源码阅读之初级篇------源码及依赖下载
    Golang(八)go modules 学习
    SQLAIchemy(二)ORM 相关
    SQLAIchemy 学习(一)Session 相关
  • 原文地址:https://www.cnblogs.com/dear_diary/p/6714077.html
Copyright © 2020-2023  润新知