? 给你一个数组,第一个元素为第一个矩阵的行数,末尾元素为最后一个矩阵的列数,中间元素为前一个矩阵的列数和后一个举证的行数。现在要将这些矩阵相乘,要求你求出最少需要做多少次乘法才能得到结果。(矩阵的乘法满足结合律)。
? 例如,对于输入的一个数组 {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];
}
}
原文:https://www.cnblogs.com/FatalFlower/p/15151656.html