package org.loda.dynamic;
import org.junit.Test;
/**
*
* @ClassName: MatrixChainOrder
* @Description: 矩阵连乘
*
* 动态规划问题
*
* 矩阵A1A2...An,求矩阵上述矩阵相乘的效率最高(标量相乘次数最少)的方案,并求出相乘次数
*
* @author minjun
* @date 2015年5月18日 上午11:12:34
*
*/
public class MatrixChainOrder {
@Test
public void testMatrix(){
//第一个元素表示第一个矩阵的行数,后面的元素表示矩阵的列数
int[] matrix={30,35,15,5,10,20,25};
int len=matrix.length;
//f[i][j]表示矩阵链Ai....Aj连乘的最优解所需要的连乘次数
int[][] f=new int[len][len];
//s[i][j]表示矩阵链Ai...Aj连乘的最优切分点为k时k的位置
int[][] s=new int[len][len];
matrixChainOrder(matrix,f,s);
int i=1,j=6;
System.out.println("矩阵链A"+i+"...A"+j+"最少标量相乘次数为:"+f[i][j]);
//将最优策略打印出来
System.out.println("最优策略为:");
printStrategy(s,i,j);
}
private void printStrategy(int[][] s, int i, int j) {
if(i>=j){
//当只有一个矩阵的时候,打印该矩阵
System.out.print("A"+i);
return;
}
//如果还是一条长度大于1的矩阵链,那么先将需要相乘的部分用括号结合起来
int k=s[i][j];
System.out.print("(");
printStrategy(s, i, k);
printStrategy(s, k+1, j);
System.out.print(")");
}
private void matrixChainOrder(int[] matrix, int[][] f, int[][] s) {
//矩阵数量
int n=matrix.length-1;
//i=j表示只有一个矩阵,矩阵链长度为1,无需任何相乘次数,所以为0
for(int i=1;i<=n;i++){
f[i][i]=0;
}
//需要有相乘,那么矩阵链长度至少为2
for(int len=2;len<=n;len++){
//矩阵链开始位置i
for(int i=1;i<=n-len+1;i++){
//矩阵链的结束位置j
int j=i+len-1;
//将该位置的最少相乘次数先初始化为最大值,如果有比他更小的,替换该较小的值
f[i][j]=Integer.MAX_VALUE;
//最优切分点
for(int k=i;k<j;k++){
//利用公式计算f[i][j]所需的相乘次数,如果获取的相乘次数更小,那么就取该值作为f[i][j]最少相乘次数
int min=f[i][k]+f[k+1][j]+matrix[i-1]*matrix[k]*matrix[j];
if(min<f[i][j]){
f[i][j]=min;
s[i][j]=k;
}
}
}
}
}
}
输出结果:
矩阵链A1...A6最少标量相乘次数为:15125
最优策略为:
((A1(A2A3))((A4A5)A6))