下面介绍三种方法来实现矩阵连乘问题。
1.动态规划
//矩阵连乘--动态规划
public class DynamicPlan {
public static int n;
public static int[] p;
public static int[][] m;
public static int[][] s;
public static void main(String[] args)
{
System.out.println("请输入矩阵的个数:");
Scanner e = new Scanner(System.in);
n = e.nextInt();
System.out.println("请输入矩阵的行数和列数:");
p = new int[n+1];
for(int i = 0;i <= n;i++)
{
p[i] = e.nextInt();
}
m = new int[n+1][n+1];
s = new int[n+1][n+1];
matrixChain(p,n,m,s);
System.out.println("矩阵连乘的最小次数是:" + m[1][n]);
System.out.println("矩阵的连乘次序:");
Traceback(1,n,s);
}
public static void matrixChain(int p[],int n,int[][] m,int[][] s)
{
for(int i = 1;i <= n;i++)//初始化,矩阵长度为1时,从i到i的矩阵连乘子问题只有一个矩阵,操作次数是0
{
m[i][i] = 0;
}
for(int r = 2;r <= n;r++)//矩阵的的长度,从长度2开始逐渐变长
{
for(int i = 1;i <= n-r+1;i++)//从第i个矩阵开始,长度为r,则矩阵为(Ai-A(i+r-1))
{
int j = i+r-1;
m[i][j] = m[i+1][j] + p[i-1]*p[i]*p[j]; //先认为在Ai到Ai-1之间断开
s[i][j] = i;//断点的索引
for(int k = i+1;k < j;k++)//k从i+1循环找m[i][j]的最小值
{
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;//最小值的断开点
}
}
}
}
}
public static void Traceback(int i,int j,int[][] s)//递归构造最优解
{
if(i == j)
{
return ;
}
Traceback(i,s[i][j],s);
Traceback(s[i][j]+1,j,s);
System.out.println("Multiply A" + i + "," + s[i][j] + "and A" + (s[i][j]+1) + "," + j);
}
}
2.递归
//矩阵连乘--递归
public class Recursion {
public static int n;
public static int[] p;
public static int[][] s;
public static int recursion(int i,int j){
if(i==j)
{
return 0;
}
int u=recursion(i+1,j)+ p[i-1]*p[i]*p[j]; //先认为在Ai到Ai-1之间断开
s[i][j] = i;//断点的索引
for(int k = i+1;k < j;k++)//k从i+1循环找最小数乘次数
{
int t = recursion(i,k)+recursion(k+1,j)+ p[i-1]*p[k]*p[j];
if(t < u)//找到比原来的断开点更小的值
{
u = t;
s[i][j] = k;//最小值的断开点
}
}
return u;
}
public static void Traceback(int i,int j,int[][] s)//递归构造最优解
{
if(i == j)
{
return ;
}
Traceback(i,s[i][j],s);
Traceback(s[i][j]+1,j,s);
System.out.println("Multiply A" + i + "," + s[i][j] + "and A" + (s[i][j]+1) + "," + j);
}
public static void main(String[] args)
{
System.out.println("请输入矩阵的个数:");
Scanner e = new Scanner(System.in);
n = e.nextInt();
System.out.println("请输入矩阵的行数和列数:");
p = new int[n+1];
for(int i = 0;i <= n;i++)
{
p[i] = e.nextInt();
}
s = new int[n+1][n+1];
System.out.println("矩阵连乘的最小次数是:" +recursion(1,n));
System.out.println("矩阵的连乘次序:");
Traceback(1,n,s);
}
}
3.备忘录
//矩阵连乘--备忘录方法
public class Memorized {
public static int n;
public static int[] p;
public static int[][] s;
public static int[][] m;
//初始化,为每个子问题建立一个记录项
public static int mematrixChain(int n) {
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
m[i][j]=0;
}
}
return lookupchain(1,n);
}
public static int lookupchain(int i,int j){
//若该子问题被计算过,直接取出该子问题的值
if(m[i][j]>0)
{
return m[i][j];
}
if(i == j)
{
return 0;
}
m[i][j]=lookupchain(i+1,j)+ p[i-1]*p[i]*p[j]; //先认为在Ai到Ai-1之间断开
s[i][j] = i;//断点的索引
for(int k = i+1;k < j;k++)//k从i+1循环找最小数乘次数
{
int t = lookupchain(i,k)+lookupchain(k+1,j)+ p[i-1]*p[k]*p[j];
if(t < m[i][j])//找到比原来的断开点更小的值
{
m[i][j] = t;
s[i][j] = k;//最小值的断开点
}
}
return m[i][j];
}
public static void Traceback(int i,int j,int[][] s)//递归构造最优解
{
if(i == j)
{
return ;
}
Traceback(i,s[i][j],s);
Traceback(s[i][j]+1,j,s);
System.out.println("Multiply A" + i + "," + s[i][j] + "and A" + (s[i][j]+1) + "," + j);
}
public static void main(String[] args)
{
System.out.println("请输入矩阵的个数:");
Scanner e = new Scanner(System.in);
n = e.nextInt();
System.out.println("请输入矩阵的行数和列数:");
p = new int[n+1];
for(int i = 0;i <= n;i++)
{
p[i] = e.nextInt();
}
s = new int[n+1][n+1];
m = new int[n+1][n+1];
System.out.println("矩阵连乘的最小次数是:" +mematrixChain(n));
System.out.println("矩阵的连乘次序:");
Traceback(1,n,s);
}
}