zoukankan      html  css  js  c++  java
  • 动态规划(三)--矩阵链乘法

    问题描述:

    给定n个矩阵的链<A1,A2,...,An>,矩阵Ai的规模为Pi-1XPi。求完全括号方案使得计算乘积所需的标量乘法次数最少。

    为了计算上式,我们可以先用括号明确计算次序,然后利用标准矩阵相乘方法进行计算。例如矩阵链<A1,A2,A3,A4,A5>,由于矩阵乘法满足结合律,所以可以有((A1A2)(A3A4)A5)或(A1(A2(A3A4))A5)等计算次序。而对于相容的矩阵A,B,若A矩阵为p*q,B矩阵为q*r,那么乘积C是p*r的矩阵,而计算时间是标量乘法的次数决定的即p*q*r。假设有三个矩阵的规模为10*100,100*5,5*50,如果按照((A1A2)A3)的顺序计算则需要7500次标量乘法,若按(A1(A2A3))次序计算,需要75000次乘法,时间相差了十倍。。要明确的是我们的目标是确定代价最低的计算顺序,并不是真正进行矩阵相乘。

    令P(n)表示可供选择的括号化方案的数量,则p(n)=1(n=1);

         p(n)=∑p(k)p(n-k) (n>=2);

    对应第一篇的原理,

    Step1:我们要寻找最优子结构,对应Ai~Aj(i<j),为了对Ai...Aj进行括号化,需要在某个Ak和Ak+1之间将矩阵链分开,然后在计算乘积得到结果Aij,即原问题可以分解成为两个互不相干的子问题并分别进行独立求解

    Step2:一个递归的求解方案

    显然最低代价m[i,j]=0(i=j)   ;   m[i,j]=min{m[i,k]+m[k+1,j]}+Pi-1PkPj(i<j)

    step3:计算最优代价

    采用子底向上的方法,用一个一维数组p[n+1]来表示矩阵链,用一个二维数组m[i][j]来保存代价,用另一个辅助二维数组s[i][j]记录最优值对应的分割点k,我们就可以用s来构造最优解了

    pseudoCode

    MATRIX-CHAIN-ORDER(p)

    n = p.length -1

      let m and s be new tables

    for i = 1  to n

    m[i][i] = 0

    for l = 2 to n

    for i =1 to n-l+1

    j=i+l-1

    m[i,j] = max

    for k = i to j-1

    q=m[i,k]+m[k+1,j]}+Pi-1PkPj

     ifq<m[i,j]

    m[i,j] = q

    s[i,j] = k

    return m and s


    java代码

    import java.util.Arrays;
    
    
    /**
     * @author Bangwen Chen
     *
     * 2013-8-22
     */
    public class Matrix_chain_order {
    	public static void main(String [] args){
    		int[]p = {30,35,15,5,10,20,25};
    		chain_order(p);
    	}
    	static void chain_order(int []p){
    		final double MAX=1E10f;
    		int n = p.length-1;
    		 double [][]m = new double[n+1][n+1];
    		double [][]s = new double [n+1][n+1];
    		for(int i=1;i<n+1;i++){
    			m[i][i]=0;
    		}
    		for(int l=2;l<n+1;l++){
    			for(int i=1;i<n-l+2;i++){
    				int j=i+l-1;
    				m[i][j]=MAX;
    				for(int k=i;k<j-1+1;k++){
    					double q = (double)m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
    					System.out.println("q" + q);
    					if(q<m[i][j]){
    						m[i][j] = q;
    						s[i][j] = k;
    					}
    				}
    			}
    		}
    		display(m);
    		System.out.println("-------------------");
    		display(s);
    	}
    	static void display(double [][] array){
    		int n = array[0].length;
    		for(int i=1;i<n;i++){
    			for(int j=1;j<n;j++){
    				System.out.print(array[i][j]+" ");
    			}
    			System.out.print("
    ");
    		}
    	}
    }
    


    step 4 构造最优解,Matrix-chain-order求出了最少的标量乘法,但它并未指出如何进行这种最优代价的矩阵链乘法计算,s中保存了最优解,利用递归给出。

    pseudocode

    PRINT-OPTIMAL-PARENS(s,i,j)

    if i == j

    print Ai;

    else

    print "("

    PRINT-OPTIMAL-PARENS(s,i,s[i,j])

    PRINT-OPTIMAL-PARENS(s,s[i,j+1,j)

    print")"

    Java代码

    import java.util.Arrays;
    
    
    /**
     * @author Bangwen Chen
     *
     * 2013-8-22
     */
    public class Matrix_chain_order_display {
    	public static void main(String [] args){
    		int[]p = {30,35,15,5,10,20,25};
    		int [] array = {5,10,3,12,5,50,6};
    		chain_order(array,1,6);
    	}
    	static void chain_order(int []p,int start,int end){
    		final double MAX=1E10f;
    		int n = p.length-1;
    		 double [][]m = new double[n+1][n+1];
    		double [][]s = new double [n+1][n+1];
    		for(int i=1;i<n+1;i++){
    			m[i][i]=0;
    		}
    		for(int l=2;l<n+1;l++){
    			for(int i=1;i<n-l+2;i++){
    				int j=i+l-1;
    				m[i][j]=MAX;
    				for(int k=i;k<j-1+1;k++){
    					double q = (double)m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
    					System.out.println("q" + q);
    					if(q<m[i][j]){
    						m[i][j] = q;
    						s[i][j] = k;
    					}
    				}
    			}
    		}
    		display(m);
    		System.out.println("-------------------");
    		display(s);
    		String A[]=new String [n+1];
    		for(int z=1;z<n+1;z++){
    			A[z] = "A".concat(String.valueOf(z));
    		}
    		print_optimal_parens(s,start,end,A);
    	}
    	
    	static void display(double [][] array){
    		int n = array[0].length;
    		for(int i=1;i<n;i++){
    			for(int j=1;j<n;j++){
    				System.out.print(array[i][j]+" ");
    			}
    			System.out.print("
    ");
    		}
    	}
    	static void print_optimal_parens(double[][] s,int i,int j,String A[]){
    		
    		if(i == j){
    			System.out.print(A[i]);
    		}else{
    			System.out.print("(");
    			int tmp = (int) s[i][j];
    			print_optimal_parens(s,i,tmp,A);
    			print_optimal_parens(s,tmp+1,j,A);
    			System.out.print(")");
    		}
    	}
    }
    


    Sep 2

  • 相关阅读:
    QlikView TEXT控件固定显示图片
    Qlikview List控件
    如何实现Qlikview的增量数据加载
    SQL Server开启READ_COMMITTED_SNAPSHOT
    AX函数,将EXCEL列号转为列名
    C# 中DataGridView 绑定List<T>做数据源的操作问题
    Could not resolve this reference. Could not locate the assembly
    WinForm程序用使用List对象绑定DataGridView数据源
    C#WebBrowser控件使用教程与技巧收集
    python局部变量、全局变量,global、nolocal的区别
  • 原文地址:https://www.cnblogs.com/riskyer/p/3297298.html
Copyright © 2011-2022 走看看