蓝桥杯 算法提高 矩阵乘法 java90分版,c++100分版

本文介绍了一种使用动态规划解决矩阵连乘问题的方法,通过优化矩阵乘法顺序,以减少计算过程中的乘法操作次数。文章详细解释了状态转移方程,并提供了C++和Java的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述

  有n个矩阵,大小分别为a0*a1, a1*a2, a2*a3, ..., a[n-1]*a[n],现要将它们依次相乘,只能使用结合率,求最少需要多少次运算。
  两个大小分别为p*q和q*r的矩阵相乘时的运算次数计为p*q*r。

输入格式

  输入的第一行包含一个整数n,表示矩阵的个数。
  第二行包含n+1个数,表示给定的矩阵。

输出格式

  输出一个整数,表示最少的运算次数。

样例输入

3
1 10 5 20

样例输出

150

数据规模和约定

  1<=n<=1000, 1<=ai<=10000。

解析:

首先:

简单的动态规划 :

m[i][j]=m[i][k]+m[k+1][j]+a[i]*a[k+1]*a[j+1];

m[i][j]:决策变量  矩阵i乘到 j的最小乘的次数

i ,j 状态转移变量

a[i]:矩阵i的行数,a[i+1]是矩阵i的列数,因为如果两个矩阵要想相乘,那么前矩阵的列数必定等于后矩阵的行数

其次:

1<=ai<=10000,而我们可以看出状态转移方程式中有a[i]*a[k+1]*a[j+1],其值最大为1e12 显然大于int类型,这里要特别指出在c++和java中,如果出现long long (c++)或者long (java)(都是64位) temp=10000*10000*10000 右边的乘号的值默认保存在int中,然后赋值给temp,这就导致temp!=1e12而是一个随机数。因而a[]数组要设为long long 或 long 

接着上面的,java中 long不能直接赋值  如long temp=1000000000000 会报错,原因同上,可以通过long inf=10000 ;long INF=inf*inf*inf的方式赋值。

c++代码如下:

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

long long dp(long long a[],int n)
	{
		long long m[n+5][n+5];//m[i][j] 从矩阵i乘到矩阵j需要的最小乘数
		long long INF=1e15+5;//10000*10000*10000*1000

		for(int i=0;i<n;i++)//初始化
            {
                for(int j=0;j<n;j++)
                    m[i][j]=INF;
                m[i][i]=0;
            }

		for(int len=1;len<n;len++)//连乘的矩阵位置之差
		{
			for(int i=0;i<n-len;i++)
			{
				int j=i+len;
				for(int k=i;k<j;k++)
				{
					long long t=m[i][k]+m[k+1][j]+a[i]*a[k+1]*a[j+1];
                    //将[i,j)之间的矩阵依次当做中间矩阵
					if(t<m[i][j])//如果t<m[i][j],更新
						m[i][j]=t;
                   //本来还得加个标记s[i][j]=k,因为只是求最小值而非打印出来具体情况 所以省了
				}
			}
		}
		return m[0][n-1];
	}
	//矩阵连乘 动态规划
	int main(){
		int n;
		cin>>n;
		long long a[1005];
		for(int i=0;i<n+1;i++)
			cin>>a[i];//行数
		cout<<dp(a,n)<<endl;
		return 0;
	}

测试情况:

1正确10.000ms948.0KB输入 输出
2正确10.000ms948.0KBVIP特权
3正确10.000ms1.0MBVIP特权
4正确10.0015ms1.238MBVIP特权
5正确10.0046ms1.625MBVIP特权
6正确10.00109ms2.167MBVIP特权
7正确10.00218ms2.867MBVIP特权
8正确10.00734ms4.707MBVIP特权
9正确10.001.093s5.859MBVIP特权
10正确10.002.421s8.621MBVIP特权

java代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;


public class Main {

	
	static Long dp(long a[],int n)
	{
		long m[][]=new long[n][n];//m[i][j] 从矩阵i乘到矩阵j需要的最小乘数
		long inf=10000;
		long INF=inf*inf*inf*inf/10+5;
		for(int i=0;i<n;i++)//初始化
			{
				Arrays.fill(m[i], INF);
				m[i][i]=0;
				//System.out.println(INF);
			}
		for(int len=1;len<n;len++)//连乘的矩阵位置之差 有点floyd算法的感觉
		{
			for(int i=0;i<n-len;i++)
			{
				int j=i+len;
				for(int k=i;k<j;k++)
				{
					long t=m[i][k]+m[k+1][j]+a[i]*a[k+1]*a[j+1];
            //将[i,j)之间的矩阵依次当做中间矩阵
					if(t<m[i][j])//如果t<m[i][j],更新
						m[i][j]=t;
            //本来还得加个标记s[i][j]=k,因为只是求最小值而非打印出来具体情况 所以省了
				}
			}
		}
		return m[0][n-1];
	}
	//矩阵连乘 动态规划
	public static void main(String[] args) throws IOException {
		int n;
		BufferedReader bfr=new BufferedReader(new InputStreamReader(System.in));
        //加快输入
		String str=bfr.readLine();
		String s[]=str.split(" ");
		n=Integer.parseInt(s[0]);
		long a[]=new long[n+1];
		str=bfr.readLine();
		s=str.split(" ");
		for(int i=0;i<n+1;i++)
			a[i]=Long.parseLong(s[i]);//行数
		System.out.println(dp(a,n));
	}

}

评测详情:

1正确10.00187ms19.13MB输入 输出
2正确10.00125ms19.03MBVIP特权
3正确10.00156ms19.35MBVIP特权
4正确10.00265ms19.97MBVIP特权
5正确10.00265ms20.5MBVIP特权
6正确10.00343ms21.08MBVIP特权
7正确10.00312ms21.67MBVIP特权
8正确10.00812ms23.5MBVIP特权
9正确10.001.468s24.50MBVIP特权
10运行超时0.00运行超时27.53MBVIP特权

感受:

1.以后做题要考虑边界条件,对于数据范围要敏感一点,要不好难满分啊!!!

2.java虽然功能强大,但却是效率没有c++高。android与ios之战??? 哈哈哈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值