[蓝桥杯][历届试题 PREV-26]最大子阵(Java)(动态规划-最大子矩阵)

历届试题 最大子阵  

时间限制:1.0s   内存限制:256.0MB

    

问题描述

  给定一个n*m的矩阵A,求A中的一个非空子矩阵,使这个子矩阵中的元素和最大。

  其中,A的子矩阵指在A中行和列均连续的一块。

输入格式

  输入的第一行包含两个整数n, m,分别表示矩阵A的行数和列数。
  接下来n行,每行m个整数,表示矩阵A。

输出格式

  输出一行,包含一个整数,表示A中最大的子矩阵中的元素和。

样例输入

3 3
-1 -4 3
3 4 -1
-5 -2 8

样例输出

10

样例说明

  取最后一列,和为10。

数据规模和约定

  对于50%的数据,1<=n, m<=50;
  对于100%的数据,1<=n, m<=500,A中每个元素的绝对值不超过5000。


解题思路:

想想类似的题型,求一个一维数组的最大连续和,这个应该是不难的。代码如下:

        //max是最后结果,arr是数组,m是arr数组长度
		int max = Integer.MIN_VALUE;
		void getMax(int[] arr, int m) {
			int temp = 0;
			for(int mi=0;mi<m;++mi) {
				temp += arr[mi];
				max = max>temp?max:temp;
				if(temp < 0)temp = 0;
			}
		}

现在的情况就是把一维拓展成了二维数组,因为最后要求的是矩阵,也就是说只要把矩阵压缩成一个一维数组就好了,三层循环:1、起始的行数,2、终止的行数,3、每列。然后把每次生成的一位数组求最大连续和,找到所有max的最大值。

说起来好像也没用到动态规划。。。。

反思错误:

①幸亏这题的数据量不大,不然我的方法绝对超时【O(m n^2)】

②因为题型是动态规划,一直向动态规划的想法上靠,结果没想出来。我这解法也不算动态规划,挂羊头卖狗肉了。不过动态规划的最大子矩阵问题是可以这么解的。

Java代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
	public static void main(String[] args) {
//		long sta = System.nanoTime();

		InputStream is = System.in;
		OutputStream os = System.out;

		IN cin = new IN(is);
		PrintWriter cout = new PrintWriter(os);

		SO so = new SO();
		so.solution(cin, cout);

//		long end = System.nanoTime();
//		cout.println("耗时:" + (double)(end-sta)/1e6 + "ms");

		cout.close();
	}

	
	
	
	
	static final int MOD = (int)1e9 + 7;
	//实际代码开始的类--------------------------------------------------
	static class SO {
		int max = Integer.MIN_VALUE;
		void getMax(int[] arr, int m) {
			int temp = 0;
			for(int mi=0;mi<m;++mi) {
				temp += arr[mi];
				max = max>temp?max:temp;
				if(temp < 0)temp = 0;
			}
		}
		void solution(IN cin, PrintWriter cout) {
			int n = cin.nextInt(), m = cin.nextInt();
			int[][] mat = new int[n][m];
			int[] arr = new int[m];
			
			for(int ni=0;ni<n;++ni) {
				for(int mi=0;mi<m;++mi) {
					mat[ni][mi] = cin.nextInt();
				}
			}
			
			for(int sni=0;sni<n;++sni) {
				Arrays.fill(arr,0);
				for(int eni=sni;eni<n;++eni) {
					for(int mi=0;mi<m;++mi) {
						arr[mi] += mat[eni][mi];
					}
					getMax(arr,m);
				}
			}
			
			cout.println(max);
		}//end solution
	}//end SO
	
	
	
	
	
	
	
	
	
	//以下是快读部分
	static class IN {
		private BufferedReader reader;
		private StringTokenizer tokenizer;

		IN(InputStream is) {
			reader = new BufferedReader(new InputStreamReader(is), 32768);
			tokenizer = null;
		}
		
		public String next() {
			while (tokenizer == null || !tokenizer.hasMoreTokens()) {
				try {
					tokenizer = new StringTokenizer(reader.readLine());
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
			return tokenizer.nextToken();
		}

		public int nextInt() {
			return Integer.parseInt(next());
		}

		public long nextLong() {
			return Long.parseLong(next());
		}

		public double nextDouble() {
			return Double.parseDouble(next());
		}

	}
}

测试结果:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值