-
题目描述:
-
已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵,你的任务是找到最大的非空(大小至少是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.youkuaiyun.com/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;
}
}