分解最优解的结构
将矩阵连乘A1A2···An用A[1:n]来表示,将其分解为A[1:k]与A[k+1:n],即先计算A[1:k]的计算量,再加上A[k+1:n]的计算量,然后再加上A[1:k]与A[k+1:n]相乘的计算量即可。
建立递归关系
当i<j时,设A[i:j]所需最少的相乘次数为m[i][j],所有可将其分解为m[i][j]=m[i][k]+m[k+1][j]+pi*pk*pj,其中pi*pk*pj为划分的两个相乘的矩阵相乘的次数。
public static void matrixChain(int []p,int [][]m,int [][]s){
int n=p.length-1;
// 初始化对角线上的子问题规模为1时的最小代价为0
for (int i = 1; i <=n; i++) {
m[i][i]=0;
}
// 计算其他子问题规模下的最小代价和括号位置
for(int r=2;r<=n;r++){//注意r为链长
for(int i=1;i<n-r+1;i++){
int j=i+r-1;
// 将问题划分为两部分:i~k 和 k+1~j,使用k将其中间劈开
// 更新最小代价和括号位置
m[i][j]=m[i][i]+m[i+1][j]+p[i-1]*p[i]*p[j];
s[i][j]=i;
// 遍历所有可能的k,更新最小代价和括号位置
for (int k = i+1; k <j ; k++) {
int t=m[i][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;
}
}
}
}
}
中间两个循环是用来计算矩阵连乘问题的最小代价和最优括号位置的。
第一个循环从规模为2的矩阵链开始,逐步增大规模,直到整个矩阵链的规模。这样做是为了按照规模大小的顺序解决子问题,确保在计算某个规模的矩阵链时,其子问题的最小代价已经计算出来。
第二个循环从左边界i开始,逐步向右移动,枚举间隔位置k来切分问题。这里的i表示矩阵链的起始位置,j表示矩阵链的结束位置。通过枚举不同的间隔位置k,可以将矩阵链划分为两部分:左边区间i~k和右边区间k+1~j。在每次迭代中,计算当前划分方式下的代价,并与之前保存的最小代价进行比较,更新最小代价和最优括号位置。
通过这两个循环的嵌套迭代,不断计算并更新子问题的最小代价和最优括号位置,最终得到整个矩阵连乘问题的最小代价和最优括号位置。将得到的最优括号位置用于构建最优的矩阵连乘序列,即可获得最优解。