動態規划問題(八)最少矩陣乘法次數


問題描述

​ 給你一個數組,第一個元素為第一個矩陣的行數,末尾元素為最后一個矩陣的列數,中間元素為前一個矩陣的列數和后一個舉證的行數。現在要將這些矩陣相乘,要求你求出最少需要做多少次乘法才能得到結果。(矩陣的乘法滿足結合律)。

​ 例如,對於輸入的一個數組 {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];
        }
    }
    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM