矩阵连乘题解


题目

    计算一系列矩阵相乘所需要的最少步骤数。

题目分析

    两个矩阵相乘的必要条件是第一个矩阵的列和第二个矩阵的行相同。假设第一个矩阵是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());
    }
}

运行结果

在这里插入图片描述
在这里插入图片描述
y9ibG9nLmNzZG4ubmV0L3FxXzQ1Nzg2OTQ1,size_16,color_FFFFFF,t_70)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星辰的野望

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值