/**
* 动态规划_矩阵连乘问题
* @author Matt
*
*/
public class Dp {
/**
* 矩阵链计算
* @param p 矩阵的长度
* @param m 矩阵的最优连乘次数
* @param s 矩阵的最优断开位置
*/
public static void matrixChain(int []p, int [][]m, int [][]s) {
// n是矩阵的长度
int n = p.length - 1;
// 将对角线的最优次数置0,因为m[i][i]的连乘次数为0
for (int i = 1; i <= n; i++) {
m[i][i] = 0;
}
// r是矩阵链的长度,有r个矩阵相乘
for (int r = 2; r <= n; r++) {
for (int i = 1; i <= n-r+1; i++) {
int j = i+r-1; // j是矩阵链的最后一个矩阵的坐标
// 计算连乘次数,i为断开处
m[i][j] = m[i+1][j] + p[i-1]*p[i]*p[j];
s[i][j] = i; // 将断开坐标i传入s数组
// 计算最优连乘次数
for (int k = i+1; k < j; k++) {
int t = m[j][k] + m[k+1][j] + p[i-1]*p[k]*p[j];
if (t < m[i][j]) {
m[i][j] = t; // 求得最优连乘次数
s[i][j] = k; // 求得最优断开位置
}
}
}
}
}
/**
* 回溯递归求得最优计算次序
* @param s 断开位置数组
* @param i 行
* @param j 列
*/
public static void traceBack(int [][]s, int i, int j) {
if (i == j) return;
traceBack(s, i, s[i][j]);
traceBack(s, s[i][j]+1, j);
System.out.println("Multiply A" + i + "," + s[i][j] +
"and A" + (s[i][j] + 1) + "," + j);
}
public static void main(String[] args) {
int[] p = {30, 35, 15, 5, 10, 20, 25}; // 矩阵维度
int n = p.length;
int[][] m = new int[n][n];
int[][] s = new int[n][n];
matrixChain(p, m, s);
traceBack(s, 1, n-1);
}
}
输出结果:
Multiply A1,1and A2,2
Multiply A1,2and A3,3
Multiply A4,4and A5,5
Multiply A4,5and A6,6
Multiply A1,3and A4,6