题目
计算一系列矩阵相乘所需要的最少步骤数。
题目分析
两个矩阵相乘的必要条件是第一个矩阵的列和第二个矩阵的行相同。假设第一个矩阵是pq,第二个矩阵是qr,那么所需要的计算步骤是pqr次。
因此假设有n个矩阵,只需要n+1个空间就可以表征这些矩阵的性质。为了便于下标处理,矩阵从下标1开始。
变量说明
p数组
记录矩阵的规模,每一个元素对应相应下标矩阵的一维长度,最后一个元素是最后一个剧真的二维长度。
dp【i】【j】
从小标i到j的矩阵相乘的步骤数,因为是求最小值,所以给一个大的初值,矩阵自己不和自己相乘,所以对角线值为0。
核心思想分析
还是有分治的思想。从两个矩阵开始连乘,计算出结果并保存起来,规模扩大到两个,调用之前/查询之前计算出来的结果,取多种可能的最小值,当规模扩大到n的时候,对应下标dp【1】【n】的值就是结果。自底向上体现在从规模小开始,记录结果留给规模大的查看。
每次规模扩大有两种情况:
如果原来的规模不进行划分,直接并上新加入的元素,那么就等于原来规模的结果加上合并的开销。
如果在新的规模上重新进行划分,那么就设立标志k,从k位置切开,两个更小的部分规模小于备忘录的最大规模,是可以查得到的,所以直接查,加上合并的规模。
代码
package Algorithms_算法.实验.动规;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
/**
* @author Xinchen Liu
* @date 2021/5/31 9:25
*/
//a[ai][aj],b[bi][bj]相乘的递推式
public class Multiple_Matrix {
ArrayList<int[][]> matrix_set = new ArrayList<>();
int[][] dp;//dp【i】【j】:从i到j的计算量,同样舍弃 0的那一行那一列
int[][] ans;
int[] p;//矩阵的宽度,第0个元素舍弃,1-size是对应矩阵的一维宽度,最后一位是最后一个矩阵的二维宽度
int j=0;
public int solve(){
p = new int[matrix_set.size()+2];
for(int i=1;i<=matrix_set.size();i++){
p[i] = matrix_set.get(i-1).length;
}//存储第i个矩阵的行数
p[p.length-1] = matrix_set.get(matrix_set.size()-1)[0].length;
//存储最后一个矩阵的列数
System.out.println(Arrays.toString(p));
dp = new int[matrix_set.size()+1][matrix_set.size()+1];
for(int[] tmp:dp){
Arrays.fill(tmp,998);//求最小值,就赋值一个大的数
}
for(int i=1;i<dp.length;i++){
dp[i][i] = 0;//自乘不需要考虑,下表0的舍弃
}
for(int distance = 1;distance < matrix_set.size();distance++){//连乘范围
for(int i=1;i + distance <= matrix_set.size();i++){
j= i + distance;//连乘区间的右端点
dp[i][j] = Math.min(dp[i][j-1] + p[i]*p[j]*p[j+1],
dp[i+1][j] + p[i+1]*p[i+2]*p[j]);//这边其实没搞懂
//先计算不划分的情况,i到j的区间等于i到j-1的乘上第j个矩阵或者i+1到j的乘上第i个矩阵
//开始划分,i-k一组,k+1-j一组,所以k可以等于i
for(int k=i;k<j;k++){
System.out.println(i+","+j+","+k+".");
int a = dp[i][j];
int b = dp[i][k] + dp[k+1][j] + p[i]*p[k+1]*p[j+1];
System.out.println("当前最小:"+a+";本次划分的大小:"+b);
dp[i][j] = Math.min(a,b);
//i的行数,k和j的列数
}
}
}
for(int[] t:dp){
System.out.println(Arrays.toString(t));
}
return dp[1][matrix_set.size()];//从1到n的连乘次数
}
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
Multiple_Matrix demo = new Multiple_Matrix();
int[][] tmp = new int[100][];
int flag = 0;
String s;
while(true){
System.out.println("请输入矩阵");
s = reader.readLine();
if(s.equals("-1")){
break;
}
while(true){
s = reader.readLine();
if(s.equals("")){
break;
}
String[] t = s.split(" ");
tmp[flag] = new int[t.length];
for(int i=0;i<t.length;i++){
tmp[flag][i] = Integer.parseInt(t[i]);
}
flag++;
}
int[][] toadd = new int[flag][];
for(int i=0;i< toadd.length;i++){
toadd[i] = tmp[i];
}
demo.matrix_set.add(toadd);
tmp = new int[100][];
flag = 0;
}
// demo.matrix_set.add(new int[][]{{1,2},{3,4},{5,6}});//3*2
// demo.matrix_set.add(new int[][]{{1,2,3,4},{2,3,4,5}});//2*4
// demo.matrix_set.add(new int[][]{{1,2,3,4,5},{1,2,3,4,5},{1,2,3,4,5},{1,2,3,4,5}});//4*5
// demo.matrix_set.add(new int[][]{{1,2},{3,4},{5,6},{3,4},{5,6}});//5*2
System.out.println(demo.solve());
}
}
运行结果