动态规划问题(八)最少矩阵乘法次数

问题描述

​ 给你一个数组,第一个元素为第一个矩阵的行数,末尾元素为最后一个矩阵的列数,中间元素为前一个矩阵的列数和后一个举证的行数。现在要将这些矩阵相乘,要求你求出最少需要做多少次乘法才能得到结果。(矩阵的乘法满足结合律)。

​ 例如,对于输入的一个数组 {40, 20, 30, 10, 30},表示输入的矩阵为 \(A(10, 20)、B(20, 30)、C(30, 10)、D(10, 30)\),最少需要做 26000 次乘法才能得到结果,即 (A(BC))D ——> 20*30*10 + 40*20*10 + 40*10*30 = 26000

解决思路

​ 解决该问题的方式很简单,将所有可能的结合方式一一列举出来,计算结果得到最小值即可。

  • 递归
    • 由于第一个元素的特殊性,因此需要特别处理一下
    • 当只有一个元素时,无需做任何乘法操作
  • 动态规划
    • 这是一个存在大量重复计算的问题,因此使用动态规划来处理可以明显地提高效率

实现

  • 递归

    public class Solution {
        /**
        * @param values: 矩阵地表示数组
        * @param i: 计算地开始位置,由于要处理第一个元素地特殊性,因此需要从第二个矩阵开始计算
        * @param j: 末尾元素位置索引
        */
        public static int minMultiMatrixRecur(int[] values, int i, int j) {
            if (i == j) return 0;
    
            int ans = Integer.MAX_VALUE;
            for (int k = i; k < j; ++k) {
                ans = Math.min(
                        ans,
                        minMultiMatrixRecur(values, i, k) // 这里计算的是结合的 i -> k 个矩阵
                        + minMultiMatrixRecur(values, k + 1, j) // 这里结合的是 k + 1 -> j 个矩阵
                        + values[i - 1] * values[k] * values[j] // 通过 k 将矩阵分为两部分,但是无论如何,最后这两个矩阵也是要相乘的,这里表示的就是最后的计算结果
                );
            }
    
            return ans;
        }
    }
    
  • 动态规划

    public class Solution {
        public static int minMultiMatrix(int[] values, int n) {
            int[][] dp = new int[n][n];
    
            // 截取的步长,这是为了记录重复计算的中间结果
            for (int L = 2; L < n; ++L) {
                for (int i = 1; i < n - L + 1; ++i) {
                    int j = i + L - 1; // 
    
                    dp[i][j] = Integer.MAX_VALUE; // 从 i 到 j 的最少乘法次数,注意,这里的 i 代表的是第二个元素而不是第一个
                    for (int k = i; k < j; ++k)
                        dp[i][j] = Math.min(
                                dp[i][j],
                                dp[i][k] 
                        		+ dp[k + 1][j] 
                        		+ values[i - 1] * values[k] * values[j] // 与上文递归的方式相对应
                        );
                }
            }
    
            return dp[1][n - 1];
        }
    }
    
posted @ 2021-08-17 11:47  FatalFlower  阅读(608)  评论(0编辑  收藏  举报