动态规划实例(十):矩阵连乘

   
给定n个矩阵{A1,A2,…,An},其中Ai与Ai+1是可乘的,i=1,2,…,n-1。考察这n个矩阵的连乘积A1A2…An。由于矩阵乘法满足结合律,故计算矩阵的连乘积可以有许多不同的计算次序,这种计算次序可以用加括号的方式来确定。若一个矩阵连乘积的计算次序完全确定,则可以依此次序反复调用2个矩阵相乘的标准算法(有改进的方法,这里不考虑)计算出矩阵连乘积。若A是一个p×q矩阵,B是一个q×r矩阵,则计算其乘积C=AB的标准算法中,需要进行pqr次数乘。
    例如,如果我们有四个矩阵A,B,C和D,我们将有:
       (ABC)D =(AB)(CD)= A(BCD)= ….
    不同组合得到的运算次数是不同的,例如A为  10 × 30 , B为 30 × 5 , C 为 5 × 60 那么
    1 (AB)C = (10×30×5) + (10×5×60) = 1500 + 3000 = 4500 次运算
    2 A(BC) = (30×5×60) + (10×30×60) = 9000 + 18000 = 27000 次运算
很明显第一种运算更为高效。
    问题:给定一个数组P[]表示矩阵的链,使得第i个矩阵Ai  的维数为 p[i-1] x p[i].。我们需要写一个函数MatrixChainOrder()返回这个矩阵连相乘最小的运算次数。
示例:
   输入:P [] = {40,20,30,10,30}  
   输出:26000 
   有4个矩阵维数为 40X20,20X30,30×10和10X30。
   运算次数最少的计算方式为:
   (A(BC))D  – > 20 * 30 * 10 +40 * 20 * 10 +40 * 10 * 30
   输入:P[] = {10,20,30,40,30}
   输出:30000
   有4个矩阵维数为 10×20,20X30,30X40和40X30。
   运算次数最少的计算方式为:
      ((AB)C)D  – > 10 * 20 * 30 +10 * 30 * 40 +10 * 40 * 30
      
1)最优子结构:
    一个简单的解决办法是把括号放在所有可能的地方,计算每个位置的成本,并返回最小值。对于一个长度为n的链,我们有n-1种方法放置第一组括号。
    例如,如果给定的链是4个矩阵。让矩阵连为ABCD,则有3种方式放第一组括号:A(BCD),(AB)CD和(ABC)D。
    所以,当我们把一组括号,我们把问题分解成更小的尺寸的子问题。因此,这个问题具有最优子结构性质,可以使用递归容易解决。
2)重叠子问题


具体实例及实现代码如下所示:

/**  * @Title: MatrixChainOrder.java  * @Package dynamicprogramming  * @Description: TODO  * @author peidong  * @date 2017-6-7 上午9:38:05  * @version V1.0  */ package dynamicprogramming;

/**  * @ClassName: MatrixChainOrder  * @Description: 矩阵连乘问题  * @date 2017-6-7 上午9:38:05  *  */  public class MatrixChainOrder {

    /**  *  * @Title: matrixChain  * @Description: 动态规划矩阵连乘次数  * @param p  * @param m  * @param s  * @return void  * @throws  */  public static void matrixChain(int[]p, int[][]m, int [][]s)
    {
        int n=p.length-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] = 999999999;
                s[i][j] = i;
                for (int k = i; k < j; k++) {
                    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;}
                }
            }
    }
    /**  *  * @Title: TraceBack  * @Description: 最优解  * @param s  * @param i  * @param j  * @return void  * @throws  */  public static void TraceBack(int [][]s, int i, int j)
    {
        if(i!=j){
            TraceBack(s,i,s[i][j]);
            TraceBack(s,s[i][j]+1,j);
            System.out.println("Multiply  A["+i+":"+s[i][j]+"] and  A["+(s[i][j]+1)+":"+j+"]");
        }
    }
    /**  *  * @Title: OptimalParens  * @Description: 打印求解过程  * @param s  * @param i  * @param j  * @return void  * @throws  */  public static void OptimalParens(int[][] s,int i,int j){
        if(i==j)
            System.out.print("(A"+i);
        else{
            OptimalParens(s,i,s[i][j]);
            OptimalParens(s,s[i][j]+1,j);
            System.out.print(")");
        }
    }

    /**  *  * @Title: main  * @Description:测试用例  * @param agrs  * @return void  * @throws  */  public static void main(String agrs[])
    {
        int[] p={30,35,15,5,10,80,25,65,40,20};
        int n=p.length;
        int [][]m=new int [n][n];
        int [][]s=new int [n][n];

        matrixChain(p, m, s);
        System.out.println("该矩阵阶乘子问题数乘的次数:");
        for(int i=1;i<m.length;i++){
            for(int j=1;j<m.length;j++){
                if(i>j)
                {
                    System.out.print("----"+"\t");
                }
                else
                {
                    System.out.print(m[i][j]+"\t");
                }
            }
            System.out.println();
        }
        System.out.println();
        System.out.println("该矩阵阶乘子问题数乘的次数:");
        for(int i=1;i<s.length;i++){
            for(int j=1;j<s.length;j++){
                if(i>j)
                {
                    System.out.print("----"+"\t");
                }
                else
                {
                    System.out.print(s[i][j]+"\t");
                }
            }
            System.out.println();
        }
        System.out.println();
        System.out.println("该矩阵阶乘的最优解:");
        TraceBack(s,1,n-1);
        OptimalParens(s,1,n-1);
    }
}

    原文作者:动态规划
    原文地址: https://blog.csdn.net/u012845311/article/details/73379638
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞