九度题目1139:最大子矩阵

题目描述:

已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵,你的任务是找到最大的非空(大小至少是1 * 1)子矩阵。
比如,如下4 * 4的矩阵

0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2

的最大子矩阵是

9 2
-4 1
-1 8

这个子矩阵的大小是15。

输入:

输入是一个N * N的矩阵。输入的第一行给出N (0 < N <= 100)。
再后面的若干行中,依次(首先从左到右给出第一行的N个整数,再从左到右给出第二行的N个整数……)给出矩阵中的N2个整数,整数之间由空白字符分隔(空格或者空行)。
已知矩阵中整数的范围都在[-127, 127]。

输出:

测试数据可能有多组,对于每组测试数据,输出最大子矩阵的大小。

样例输入:
4
0 -2 -7 0
9 2 -6 2
-4 1 -4  1
-1 8  0 -2
样例输出:
15

         一开始只知道要用DP但是没有思路,  网上找了下资料。 这篇文章  http://blog.csdn.net/beiyeqingteng 启发了我, 通过上面上述的算法, 结合自己再将算法运行的过程写出来,  初步理解了解这题的思想, 下面是代码


import java.io.BufferedInputStream;
import java.util.Scanner;

public class Main {

	/**
	 * 这题最大的难度是将最大子矩阵问题转化为最大连续子数组问题
	 * 		定义A[i1..i2][j1..j2] 为矩阵A从i1行到i2行, j1列到j2列的子矩阵
	 * 		定义S[i1..i2][j1..j2] 为矩阵A从i1行到i2行, j1列到j2列的子矩阵的和
	 * 		那么最大子矩阵就是求Max(S[i1..i2][j1..j2])
	 * 思路是将二维数据转换成一维数组求解
	 * 		即将i1到i2(或者j1到j2)的数据求和
	 * 		此时知道了i1,i2即知道了子矩阵的起始行和结束行, 剩下的就是判定子矩阵的起始列和结束列
	 * 		  	过程中记录矩阵和最大的值就是最大子矩阵
	 */
	
	/**
	 * 		计算过程, 方便理解
	 * 		Ri1i2 代表从i1行到i2行作为子矩阵
	 * 
	 * 
	 * 		 0 -2 -7  0
 	 *		 9  2 -6  2
	 *		-4  1 -4  1
	 *		-1  8  0 -2 
	 *
	 *		R00 = {0, -2, -7, 0}   MaxSubArray(R00) = 0
	 *		R01 = {9, 0, -13, 2}   MaxSubArray(R01) = 9
	 *		R02 = {5, 1, -17, 3}   MaxSubArray(R02) = 6
	 *		R03 = {4, 9, -17, 1}   MaxSubArray(R03) = 13
	 *
	 *		R11 = {9, 2, -6, 2}    MaxSubArray(R11) = 11  
	 *		R12 = {5, 3, -10, 3}   MaxSubArray(R12) = 8
	 *		R13 = {4, 11, -10, 1}  MaxSubArray(R13) = 15
	 *
	 *		R22 = {-4, 1, -4, 1}   MaxSubArray(R02) = 6
	 *		R23 = {-5, 9, -4, -1}  MaxSubArray(R02) = 6
	 *
	 *		R33 = {-1, 8, 0, -2}   MaxSubArray(R33) = 7
	 *		
	 *		在这过程中选最i1i2, j1j2 令Sum(A[i1..i2][j1..j2])最大
	 *		
	 *		由步骤可知最大子矩阵Max(A[i1..i2][j1..j2]) = 15, i1 = 1, i2=3, j1=0, j2=1	
	 */
	public static void main(String[] args) {
		Scanner cin = new Scanner(new BufferedInputStream(System.in));

		while (cin.hasNext()) {
			int n = cin.nextInt();
			int[][] array = new int[n][n];
			for (int i = 0; i < n; i++) {
				for (int j = 0; j < n; j++) {
					array[i][j] = cin.nextInt();
				}
			}

			System.out.println(maxSubMartix(array, n));
		}

		cin.close();
	}

	static int maxSubMartix(int[][] array, int n) {
		int max = Integer.MIN_VALUE;
		// 子矩阵起始行控制
		for (int i = 0; i < n; i++) {
			// 子矩阵结束行控制
			int[] r = new int[n];
			for (int k = i; k < n; k++) {
				// 将所有列的数据都放入数组
				for (int j = 0; j < n; j++) {
					r[j] += array[k][j];
				}
				//System.out.println(Arrays.toString(r) + "  " + i + ", " + k);
				max = Math.max(max, maxSubArray(r));
			}
		}
		return max;
	}

	static int maxSubArray(int[] array) {
		int max = Integer.MIN_VALUE;
		int sum = 0;
		for (int value : array) {
			sum += value;
			if (sum > max) {
				max = sum;
			}
			if (sum < 0) {
				sum = 0;
			}
		}
		return max;
	}
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值