动态规划---矩阵连乘问题

来源:互联网 发布:算法优先语法分析器 编辑:程序博客网 时间:2024/05/18 03:03

建立递归关系
设计算A[i:j],1<=i<=j<=n,所需的最少数乘次数为m[i][j],则原问题的最优值为m[1][n].
当i=j时,A[i:j]=Ai 为单一矩阵,无需计算,因此m[i][j]=0,i=1,2,…,n.
当i< j时,可利用最优子结构性质来计算m[i][j]。 若计算A[i:j]的最优次序在Ak和Ak+1之间断开,i<=k< j,则m[i][j]=m[i][k]+m[k+1][j]+pi-1pkpj.由于计算时并不知道断开点k的位置,所以k还未定。不过k的位置只有j-i个可能,因此,k是这j-i个位置中使计算量达到最小的那个位置。从而m[i][j]可以递归的定义为


m[i][j]给出了最优值,即计算A[i:j]所需的最少数乘次数。同时还确定了计算A[i:j]的最优次序中的断开位置k,也就是说,对于这个k,有
m[i][j] = m[i][k] + m[k+1][j] +pi-1pkpj

计算最优值
递归方法
时间复杂度为2的n次方。
递归做会有多次重复计算,效率会很低,数据稍大就game over

//矩阵连乘递归算法public class MatrixChain {    public static int[] p=null;//p[i]代表第i个矩阵列数,p[i-1]代表第i个矩阵行数    public int min(int a,int b){        return a<b?a:b;    }    //计算从i到j的矩阵连乘最少数乘次数    public int d(int i,int j){        if(i==j)            return 0;//i==j时,就是单个矩阵,没有连乘,最少次数为0        if(i==j-1)            return p[i-1]*p[i]*p[j];//当两个矩阵相邻时        int u=d(i,i)+d(i+1,j)+p[i-1]*p[i]*p[j];//对于从i到j的矩阵连乘,当k==i时最少数乘次数        for(int k=i+1;k<j;k++){  //i<k<j时            int t=d(i,k)+d(k+1,j)+p[i-1]*p[k]*p[j];//取得每个k对应所需的数乘次数,和当前最小值比较            u=min(t,u);        }        return u;//返回计算的最少数乘次数值    }    public static void main(String[] args) {        p=new int[]{30,35,15,5,10,20,25};//矩阵A1A2A3A4A5A6连乘        MatrixChain mc = new MatrixChain();        System.out.println(mc.d(2, 5));//A2A3A4A5最少数乘次数    }}
7125

动态规划方法
时间复杂度为n的3次方
问题具有最优子结构性质和子问题重叠性质是可用动态规划算法求解的基本要素。
最优子结构:当问题的最优解包含了其子问题的最优解,称该问题具有最优子结构性质。
重叠子问题:在用递归算法自顶向下解此问题时,每次产生的子问题并不总是新问题,有些子问题被反复计算多次。

//p[i]代表第i个矩阵列数,p[i-1]代表第i个矩阵行数 s[i][j]存储第i到第j个矩阵连乘最优断开位置的值    public void matrixChain(int[] p,int n,int[][] m,int[][] s){        for(int i=1;i<=n;i++)            m[i][i]=0;//初始化单个矩阵连乘的最小次数为0.        for(int r=2;r<=n;r++)   //r是连乘的矩阵个数,因为个数为1时没有连乘次数,上一步已经判断,所有从2开始            for(int i=1;i<=n-r+1;i++){//这里的i就是从第1个到底n-r+1个连乘矩阵的第一个矩阵坐标(这里坐标从1开始计算)                int j=i+r-1;//j就是最后一个矩阵坐标                m[i][j] = m[i+1][j]+p[i-1]*p[i]*p[j];//当k=i时,m[i][j]从矩阵i到j连乘最少数乘次数                s[i][j]=i;      //数组s记录最优断开位置k的值                for(int k=i+1;k<j;k++){//当i<k<j时                    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;                    }                }            }    }
0 0