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

问题描述

  有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.00 0ms 948.0KB 输入 输出
2 正确 10.00 0ms 948.0KB VIP特权
3 正确 10.00 0ms 1.0MB VIP特权
4 正确 10.00 15ms 1.238MB VIP特权
5 正确 10.00 46ms 1.625MB VIP特权
6 正确 10.00 109ms 2.167MB VIP特权
7 正确 10.00 218ms 2.867MB VIP特权
8 正确 10.00 734ms 4.707MB VIP特权
9 正确 10.00 1.093s 5.859MB VIP特权
10 正确 10.00 2.421s 8.621MB VIP特权

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.00 187ms 19.13MB 输入 输出
2 正确 10.00 125ms 19.03MB VIP特权
3 正确 10.00 156ms 19.35MB VIP特权
4 正确 10.00 265ms 19.97MB VIP特权
5 正确 10.00 265ms 20.5MB VIP特权
6 正确 10.00 343ms 21.08MB VIP特权
7 正确 10.00 312ms 21.67MB VIP特权
8 正确 10.00 812ms 23.5MB VIP特权
9 正确 10.00 1.468s 24.50MB VIP特权
10 运行超时 0.00 运行超时 27.53MB VIP特权

感受:

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

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

猜你喜欢

转载自blog.csdn.net/Look_star/article/details/88416401
今日推荐