动态规划之矩阵链乘

首先为什么会有矩阵链乘法:
假设有4个矩阵A1,A2,A3,A4,他们的规模分别是5X2,2X3,3X4,4X5(要想矩阵链乘必须满足矩阵行等于矩阵列,A1是一行2列的矩阵,依此类推),矩阵满足结合律,可以是(A1XA2)X(A3XA4),也可以是A1X(A2XA3)XA4,那么按照哪种方法矩阵相乘的次数最少?
显然第一种乘了2X3X5+3X4X5+4X5X5=190次,而第二种乘了2X3X4+2X4X5+4X5X5=164次。矩阵相乘的分配方法不同,计算时间也不相同,那么矩阵链乘法就是求解最佳分配方法。
矩阵规模序列:
假设一个矩阵规模序列P为{5,10,3,12,5,50,6}那么这些矩阵的规模为{5X10,10X3,3X12,12X5,5X50,50X6}。
矩阵链乘法:
动态规划是将大的复杂问题分解成小的子问题,通过对小的子问题的求最优解,得到大的复杂问题的最优解。
假设有n个矩阵A1~An,n太大了我求不出来,那么n=1时得到最优解是什么?
显然相乘次数为0,不用分配。对于n=2时,假设矩阵规模为序列为{5,10},那么很显然相乘次数为1X5X10=50次,容易计算。那么n越来越大怎么办,假设在第i个矩阵和第j个矩阵之间有一个矩阵Ak,而Ak恰好就是最佳的分割点,那么我只需要计算Ai和Ak之间的最优相乘次数和Ak与Aj之间的最优相乘次数再加上Pi-1XPkXPj就可以了。即M[i,j] = M[i,k]+M[k,j]+PiXPkXPj.矩阵M存储的是矩阵相乘最少的次数,例:M[i,j]表示Ai和Aj之间最优相乘次数。

//对于一个矩阵规模序列P为{4,60,772,4,86,58,44}
//二维数组传参数时要这样:int (*x)[数组大小](会存在内存泄漏问题导致后面的新测试数据结果相同,建议用java写,我会再写一个java版本)
void MtrixChainOrder(int P[], int(*M)[7], int(*S)[7]){
    int i, l, j, k, q;
    for (i = 1; i < 7; i++){
        //即只有一个矩阵时相乘次数为0,Ai~Ai
        M[i][i] = 0;
    }
    //寻找最佳的相乘次数,2个矩阵,3个矩阵...一直到n个矩阵,l控制矩阵长度
    for (l = 2; l < 7; l++){
        //i控制矩阵的其实位置
        for (i = 1; i < 7 - l + 1; i++){
            //j控制矩阵的结束位置
            j = i + l - 1;
            M[i][j] = 111111111;//(自己赋值控制)
            for (k = i; k < j; k++){
                q = M[i][k] + M[k + 1][j] + P[i - 1] * P[k] * P[j];
                if (q < M[i][j]){
                    //将小的赋值次数赋值给M[i,j]
                    M[i][j] = q;
                    //S记录Ai与Aj之间最佳分配位置
                    S[i][j] = k;
                }
            }
        }
    }
}

得到S数组后可以确定分割位置

//i和j可传1,6
void Print(int(*S)[7], int i, int j){
    if (i == j){
        cout << "A";
        cout << i;
    }
    else{
        cout << "(";
        Print(S, i, S[i][j]);
        Print(S, S[i][j] + 1, j);
        cout << ")";
    }
}
点赞