/**
*
* @author YuYunTan(谭淇蔚)
*定义数组P[i]
*p[i]的含义有两层
*指的是:
*1. 第i个矩阵的列
*2. 第i+1个矩阵的行
*
*思路:
*步骤:
*划分阶段(子问题)并刻画
*将原问题划分成两个子问题。如果原问题获得最优值。则子问题的应该也是最优的。
*将矩阵连乘积A1A2A3A4简记为A(1:n)
*设最优计算次序在矩阵Ak和Ak+1之间将矩阵链断开,1≤k<n,则其相应完全加括号方式为
*(A1...Ak)(Ak+1...An)
*考虑任意大小(起点为i,终点为j)的子问题
*将矩阵连乘积 AiAi+1Ai+2...Aj 简记为A(i:j) ,这里i≤j
*考察计算A(i:j)的最优计算次序。设这个计算次序在矩阵Ak和Ak+1之间将矩阵链断开,i≤k<j,则其相应完全加括号方式为
*(Ai...Ak)(Ak...Aj)
*计算量:A(i:k)的计算量加上A(k+1:j)的计算量,再加上A(i:k)和A(k+1:j)相乘的计算量。
*特征:计算A(i:j)的最优次序所包含的计算矩阵子链 A(i:k)和A(k+1:j)的次序也是最优的。
*矩阵连乘计算次序问题的最优解包含着其子问题的最优解。
*设计算A(i:j),1≤i≤j≤n,所需要的最少数乘次数m[i,j],
*设计算A(i:k)的最少数乘次数为m[i,k],计算A(k+1:j)最少数乘次数为m[K+1,j]
*最后两个矩阵相乘即A(i:k)A(k+1,j)所做的乘法次数:p[i-1]p[k]p[j]
*m[i,j]=m[i][k]+m[k+1][j+1]+p[i-1]p[k]p[j];
*
*s[i][j]中的数字k表明计算矩阵链A[i:j]的最佳方式应在矩阵A[k]和A[k+1]之间断开
*即最佳的加括号方式为(A[1:k])(A[k+1,j])
*因此s[1][n]记录的信息可知A[1:n]的最佳的加括号方式为:
*A[1:s[1][n])(A[s[1][n]:n)
*/
public class MatirxMul {
public static void main(String[] args) {
//int []p = {50,10,40,30,5};
int []p = {30,35,15,5,10,20,25};//两组数据做测试
//p[i]的含义有两层指的是:
//1. 第i个矩阵的列
//2. 第i+1个矩阵的行
int [][]m = new int [p.length+1][p.length+1];//记录连乘次数
int [][]s = new int [p.length+1][p.length+1];//记录最佳分割位置
MatrixChain(p,m,s);
System.out.println("矩阵计算量最小次数矩阵");
PrintMatrixMul(m,p.length);
System.out.println("相对于M矩阵的最优断开位置矩阵S");
PrintMatrixMul(s,p.length);
System.out.println("乘法的最优次序:");
traceback(s,1,p.length-1);
}
private static void PrintMatrixMul(int[][] m,int n) {
// TODO 自动生成的方法存根
//打印数组
for(int i = 1;i<=n-1;i++){
for(int j =1;j<=n-1;j++){
System.out.print(m[i][j]+"\t");
if(j % (n-1) ==0)System.out.print("\n");
}
}
}
public static void MatrixChain(int []p,int [][]m,int [][]s){
//计算最优值
for(int i=1;i<=p.length;i++){
m[i][i]=0;
}
for(int r = 2; r<= p.length;r++){
for(int i=1;i<=p.length-r;i++){
int j = i+r-1;
m[i][j] = m[i+1][j]+p[i-1]*p[i]*p[j];
s[i][j] = i;
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;
}
}
}
}
}
private static void traceback(int[][] s, int i, int j) {
// TODO 自动生成的方法存根
//输出最优计算次序
//观察解的格式,发现如果只有单个的A,那么只要输出Ai,前后会有括号
//如果是连续的A,则规律是i+1=j,那么此时不要使用括号
//在分割点左边是用“(”,在分割点右边是用“)”,此时采用递归去求解使用括号的位置
if(i==j)
System.out.print("A"+i);
else if(i+1==j)
System.out.print(" (A"+i+" * "+" A"+j+") ");
else{
System.out.print(" (");
traceback(s,i,s[i][j]);
traceback(s,s[i][j]+1,j);
System.out.print(") ");
}
}
}