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

    问题描述

      》给定n个矩阵{A1,A2,...,An},其中Ai与Ai+1是可乘的(即Ai的列数与Ai+1的行数相等)

      》如何确定矩阵连乘积的计算次序,使得总计算次数最少

      》用加括号方法表示矩阵连乘次序,不同加括号方法对应的计算次序是不同的

    例:

      三个矩阵A1A2A3连乘共有两种加括号的方式:(A1A2 )A3和A1 (A2A3 )

      四个矩阵A1A2A3A4连乘共有五种加括号的方式:(A1 (A2 (A3A4 )))、 ((A1A2 )(A3A4 ))、((A1 (A2A3 ))A4 )、 (A1 ((A2A3 )A4 ))及(((A1A2 )A3 )A4 )。

      设四个矩阵A, B, C和D,维数分别为A=50 × 10,B=10 × 40,C=40 ×30,D=30 × 5。

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

          (A((BC)D)):10*40*30 + 10*30*5 + 50*10*5 = 16000

          (A(B(CD))):40*30*5 + 10*40*5+50*10*5 = 10500

          ((AB)(CD)):50*10*40 + 40*30*5 + 50*40*5 = 36000

          (((AB)C)D):50*10*40 + 50*40*30 + 50*30*5 = 87500

          ((A(BC))D):10*40*30 + 50*10*30 + 50*30*5 = 34500

    采用穷举法

    采用动态规划

    第一步 分析最优解的结构

      ◼将AiAi+1…Aj记作A[i:j],假设求解A[1:n]最优计算次序 在Ak和Ak+1之间断开, k∈[1,n]. 则

      ◼完全加括号方式为((A1…Ak )(Ak+1…An ))

      ◼ 总计算量=A[1:k]的计算量 + A[k+1:n]的计算量 + A[k]的结果矩阵乘以A[k+1]的结果矩阵的计算量

      ◼最优序列的子序列划分也是最优的。假如(A1...Ak)不是最优子序列,则将比它更好的子序列与(Ak+1...An)合并后,原序列不是最优,与已知矛盾

      ◼问题的最优子结构性质是该问题可用动态规划算法 求解的显著特征

    矩阵连乘算法数据结构

      形参中应有矩阵个数n和存储矩阵行数的一维数组p[n]。因为要使矩阵可乘,Ai的列数必须与Ai+1的行数一致,所以只需用p[0]存储A1的行数,其他矩阵只存储列数即可

      算法需要两个二维数组:

        用A[i, j]表示A[i: j]的总计算量,二维数组m[n][n]存储A[i, j]的最小值,即最小数乘次数

        二维矩阵s[n][n],每个元素s[i][j]为A[i: j]的断点位置

    第二步 建立递归关系

      令m[i][j]为A[i: j]的最小数乘次数,则m[1][n]则为A[i: j]的解

      令i= j,则m[i][j]为单矩阵的数乘次数,为0

      当i< j,利用最优子结构性质有:

        m[i, j] =       0               i = j

            min(i<= k < j){m[i, k] + m[k+1, j] + Pi-1PkPj}  i < j

        k的位置只有j-i种可能

    递推算法

      MatrixChain(形参表)

      {

      初始化;//初始化是将m[i][i],即对角线元素,赋值为0

      自底向上地计算每一个m[i][j]并将结果填入表中;//底是m[i][i],即对角线元素。最顶层是m[1][n]

      }

        

    package 动态规划;
    
    import java.util.Scanner;
    
    public class 矩阵连乘 {
        static void matrixChain(int n,int p[],int m[][],int s[][])//递推
        {
           for(int i=1;i<=n;i++){//对角线先为0
            m[i][i]=0;
           }
           for(int r=2;r<=n;r++){//一共n-1个对角线
            for(int i=1;i<=n-r+1;i++){//第i行
                int j=i+r-1;//在该行的对角线上的点对应的j值,这个j控制的是矩阵链的结束位置,即A[i: j]中的j
                m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];//初始化此时在i处取得最优解,因为m[i][i]为0,所以此处没写
                s[i][j]=i;
                for(int k=i+1;k<j;k++){//如果有更小的则被替换,由于计算时并不知道k的位置,所以k未定,但只有j-i种可能,即k属于{i,i+1,...,j-1 }
                    int t=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
                    if(t<m[i][j])
                    {
                        m[i][j]=t;
                        s[i][j]=k;
                    }
                }
            }
           }
        }
        
        static void print_optimal_parents(int s[][],int i,int j)//打印划分的结果
         {
             if( i == j)
                 System.out.print("A"+i);
             else
             {
                 System.out.print("(");
                 print_optimal_parents(s,i,s[i][j]);
                 print_optimal_parents(s,s[i][j]+1,j);
                 System.out.print(")");
             }
    
         }
        
        public static void main(String argc[])
        {
            int p[] = new int[1000];//每个矩阵的行数和最后一个的列数
            int m[][] = new int[100][100];//存储最优子结构
            int s[][] = new int[100][100];//存储当前结构的最优断点
            System.out.println("请输入矩阵的个数");
            int n;
            Scanner in = new Scanner(System.in);
            n = in.nextInt();
            System.out.println("请依次输入每个矩阵的行数和最后一个矩阵的列数");
            for(int i=0;i<=n;i++){
                p[i] = in.nextInt();
            }
            matrixChain(n,p,m,s);
            System.out.println("这些矩阵相乘的最少次数是"+m[1][n]);
    
            System.out.println("结果是:");
             print_optimal_parents(s,1,n);
        }
    }

    运行结果:

           

  • 相关阅读:
    HDU 1423
    POJ 3264
    POJ 3177
    CodeForces 81A
    SPOJ RATING
    ZOJ 2588
    POJ 1523
    POJ 3667
    递归
    数据结构
  • 原文地址:https://www.cnblogs.com/LieYanAnYing/p/11708906.html
Copyright © 2011-2022 走看看