• DP之矩阵连乘问题


    最优二叉查找树的一道思考习题

    同最优二叉查找树一样,矩阵连乘问题也是一个卡特兰数问题(其动态规划的构造过程都很像)


    分析解答:
    a,铺垫的数学知识首先要搞清楚矩阵相乘是怎么乘的:

    1)对于连续的n个矩阵相乘 A1 * A2 *A3.........An,其乘法顺序可以是任意的,可以在上面加括号,改变做乘法的顺序,例如 A*B*C三个矩阵相乘可以A*(B*C)

    也可以直接按从左到右的顺序。连续的两个矩阵的位数必须满足m*p,p*n才能相乘,且相乘后的结果是个m*n的矩阵。(线性代数的知识)

    2)对于2个m*p,p*n的矩阵相乘,共做乘法次数为 m*n*p 次。这是预备知识,知道矩阵连续的乘法的运算次数跟运算顺序有关后,就很容易举出例子了,略。
    b,卡特兰数个,证明很麻烦,有时间看了组合数学再来看
    c,重点是要解决这个问题。


    设M[i , j]表示从第 i 个矩阵到第 j 个矩阵连乘的最少乘法次数,(i 从 0 编号),我们最终的目标是求 M[0 , n-1]。

    Ai *.......Ak * Ak+1.....Aj

    假设要得到这个式子的值(即从矩阵 i 连乘到矩阵 j),所作的最后一个矩阵乘法是在矩阵 k 后(注意准确的描述位置)断开的(即左右都已乘运算好),那么容易得到

    其递推式:

    M[i , j]  =  min{ M[i , k] + M[k+1 , j]  + p[i - 1] * p[ k ] * p[ j ] }         i   <=   k   <=   j-1

    其中 di 是矩阵 Ai 的第一维,dk+1是断开处矩阵 Ak 的第二维(即Ak+1的第一维,是一样的),dj+1是最后一个矩阵 Aj 的第二维。

    得到这个式子也是一个逆向思维的过程。


    可以用矩阵连乘的动态规划构造过程与最优二叉查找树比较下,发现其构造非常相似(在前面一篇dp之什么叫做professional中提到过,不再详述)

    实现:

    初始条件:M[i , i] = 0

    填表顺序:鉴于其递推式与最优二叉查找树相似,填表顺序也是按对角线的,自己画画就知道了。

    代码也跟最优二叉查找树的控制逻辑相似:

     

    package Section8;


    /*第八章 动态规划   课后习题:矩阵连乘*/

    public class MatEven {

        /**
         * @param args
         */
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            int[] Dim = {30,35,35,15,15,5,5,10,10,20,20,25};
            int result = MatEven(Dim);

            System.out.println(" 动态规划求的的最优策略相乘顺序导致的最少乘法数为:" + result);
        }
       
        public static int MatEven(int[] Dim){
            //接受n个矩阵的维度数组Dim大小为2n
            int n = Dim.length / 2;        //有n个矩阵,编号0...n-1,编号为k的矩阵的维数是Dim[2k] * Dim[2k+1]
           
            int[][] Result = new int[n][n];        //最小代价矩阵
           
            //初始化
            for(int i = 0;i < n;i++)
                Result[i][i] = 0;
           
            //沿对角线填矩阵
            for(int d = 1;d <= n-1;d++)      //共n-1条对角线需要填
            {
                for(int i = 0;i <= n-d-1;i++)    //第d条对角线的第一个点横坐标为d
                {
                    //int j = i - d;
                    int j = i + d;        //在第d条对角线上的点,横纵坐标的关系是j = i + d
                   
                    //这样就确定了一个位置(i,j)的坐标,然后来填(i,j)
                    int Min = 1000000000;
                    for(int k = i;k <= j-1;k++)        //从第k个矩阵后面断开
                    {
                        //动态规划状态转移方程
                        int temp = Result[i][k] + Result[k+1][j] + (Dim[2*i] * Dim[2*k + 1] * Dim[2*j+1]);
                        if( temp < Min)
                            Min = temp;
                    }
                   
                    Result[i][j] = Min;
                }
               
            }
           
            return Result[0][n-1];
        }
    }

     



    上面用一个数组接受一个连乘的矩阵的维数,

    例如连乘的矩阵维数是:30*35  35*15  15*5  5*10  10*20  20*25

    用动态规划求解得到的最佳乘法次数是:


    动态规划求的的最优策略相乘顺序导致的最少乘法数为:15125

    直接返回矩阵的话就可以得到整个M[i , j]的值

    如果按照从左到右的顺序做乘法,是远远不止这个次数的。


    -------------------------------------------------------------------------

    当然,再做一些处理,就还可以得到具体的次序,类似于最优二叉查找树,就是要记录动态规划产生的过程,略

    ----------------------------------------------------------------------------------------------


    总结:


    矩阵连乘问题是个卡特兰数问题

    其动态规划的构造过程非常类似于最优二叉查找树

    矩阵连乘的最有子结构是什么?

  • 相关阅读:
    Jquery 图片预览插件 imgPreview
    对request.getSession(false)的理解(附程序员常疏忽的一个漏洞)
    JavaScript拖拽实现(附注释),最经典!最简单!短小精悍!
    如何使用VC++写一个小程序来检测.NetFrameWork版本
    利用TreeView实现C#工具箱效果
    JavaScript中json对象和string对象之间的转化
    Ubuntu Server上搭建可用于生产环境的ASP.NET服务器
    winexec()函数的参数说明(c++)
    C#对文件夹的判断、创建、移动、删除
    C#程序不用安装.NET环境运行(让C#程序脱离.net框架)
  • 原文地址:https://www.cnblogs.com/yaowen/p/4466268.html
Copyright © 2020-2023  润新知