假设原二维矩阵的最大子矩阵所在行是从i到j,那么只会出现下面这2种情况:
- 当i=j时,求最大子矩阵和就转换成了求第i行元素的最大连续子序列和。
- 当i!=j时,将第i行到第j行的所有行的元素累加起来,得到只有一行的一维数组,这个一维数组的最大连续子序列和,便是最大子矩阵和。
只需要从小到大枚举并依次遍历i和j,并且记录当前最大子矩阵和,即可求得最大子矩阵和。
当i!=j时,可以使用一个辅助二维矩阵,记录原始矩阵从上到下累加起来的累加矩阵,于是求从第i行到第j行的一维数组时,只需要将辅助矩阵进行一行减法便可得到,而不需要逐行进行多次累加。
当i!=j时,可以使用一个辅助二维矩阵,记录原始矩阵从上到下累加起来的累加矩阵,于是求从第i行到第j行的一维数组时,只需要将辅助矩阵进行一行减法便可得到,而不需要逐行进行多次累加。
import java.util.*;
public class Main {
/**
* 获得一维数组array的最大连续子序列和
*/
private static int findGreatestSumOfSubArray(int[] array) {
if (array.length == 0) {
return 0;
}
int[] dp = new int[array.length];
dp[0]=array[0];
int max = array[0];
for(int i=1;i<array.length;i++){
dp[i]=Math.max(dp[i-1]+array[i],array[i]);
max=Math.max(max,dp[i]);
}
return max;
}
/**
* 获得矩阵matrix的最大子矩阵和
*/
private static int findGreatestSumOfSubMatrix(int[][] matrix) {
int[][] total = matrix;//辅助矩阵
/**
* 为了能够在原始矩阵里很快得到从 i 行到 j 行 的上下值之和,我们这里用到了一个辅助矩阵,它是原始矩阵从上到下加下来的
*/
for (int i = 0; i < matrix.length; i++) {//初始化辅助矩阵
for (int j = 0; j < matrix[0].length; j++) {
if (i == 0) {
total[i][j] = matrix[i][j];
} else {
total[i][j] += total[i - 1][j];
}
}
}
int ans = Integer.MIN_VALUE;
//最大子矩阵为i到j行,i从0到length-1,j从i到length-1
for (int i = 0; i < matrix.length; i++) {
for (int j = i; j < matrix.length; j++) {
//array 保存的是从 i 行 到第 j 行 所对应的矩阵上下值的和
int[] array = new int[matrix[0].length];
for (int k = 0; k < matrix[0].length; k++) {
//如果我们要求第 i 行到第 j 行之间上下值的和,我们可以通过total[j][k] - total[i-1][k] 得到,
//k 的范围从1 到 matrix[0].length - 1。
if (i == 0) {
//i为0,获得前j行的和
array[k] = total[j][k];
} else {
//i不为0,需要减去前i行的和,得到i行到j行的和
array[k] = total[j][k] - total[i - 1][k];
}
}
int max = findGreatestSumOfSubArray(array);
ans = Math.max(max, ans);
}
}
return ans;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int n = scanner.nextInt();
int[][] matrix = new int[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
matrix[i][j] = scanner.nextInt();
}
}
System.out.println(findGreatestSumOfSubMatrix(matrix));
}
}
}

京公网安备 11010502036488号