Skip to content

矩阵连乘方案

约 449 字大约 2 分钟

2024-11-03

传入一个一维数组,代表矩阵

思想

构建二维数组 m[n + 1] [n+1],用于动态规划查表

对于左上角到右下角的对角线初始化为0,因为对角线相当于自身与自身,长度为 1 的矩阵链不需要乘法

重要前提

假设 A:15 * 45, B:45 * 23, C: 23 * 12, D:12 * 32

那么假设在 B 与 C 处断开,即(A * B) * (C * D),那么计算次数为(A 与 B 相乘的次数) + (C 与 D 相乘的次数)+ (A 的行 * C 的行 * D 的列,即 15 * 23 * 32)

一段嵌套循环

  • r:表示矩阵链的长度,[2, n]
    • i:表示矩阵链的起始位置,[1, n + 1]
      • j:表示矩阵链的结束位置,j = r + i - 1
      • 在 i 和 i+1 处断开,并记录
      • 在该链长范围下,遍历各种断开点。k:表示可能的断开位置,[i + 1, j),若出现更好的断开位置,则更新先前记录的断开位置

代码

void dpMatrix(int[] matrix) {
        int n = matrix.length - 1;
        int[][] m = new int[n + 1][n + 1];
        int[][] s = new int[n + 1][n + 1];
        // 初始化边界
        for (int i = 0; i <= n; ++i) {
            m[i][i] = 0;
        }
 
        for (int r = 2; r <= n; ++r) {
            for (int i = 1; i <= n + 1 - r; ++i) {
                int j = r + i - 1;
                // 在 i 与 i+1 处分隔
                m[i][j] = m[i + 1][j] + matrix[i - 1] * matrix[i] * matrix[j];
                s[i][j] = i;

                for (int k = i + 1; k < j; ++k) {
                    int temp = m[i][k] + m[k + 1][j] + matrix[i - 1] * matrix[k] * matrix[j];
                    if (temp < m[i][j]) {
                        m[i][j] = temp;
                        s[i][j] = k;
                    }
                }
            }
        }
        System.out.println("最小计算量: " + m[1][matrix.length - 1]);
        System.out.print("最佳分隔位置为: ");
        print(s, 1, matrix.length - 1);
    }

    void print(int[][] s, int i, int j) {
        if (i == j) {
            System.out.print("A" + i);
        } else {
            System.out.print("(");
            print(s, i, s[i][j]);
            print(s, s[i][j] + 1, j);
            System.out.print(")");
        }
    }