描述 给定一个由整数组成二维矩阵(r*c),现在需要找出它的一个子矩阵,使得这个子矩阵内的所有元素之和最
大,并把这个子矩阵称为最大子矩阵。例子: 0 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2 其最大子矩阵
为: 9 2 -4 1 -1 8 其元素总和为15。 输入 第一行输入一个整数n(0<n<=100),表示有n组测试数据; 每组
测试数据: 第一行有两个的整数r,c(0<r,c<=100),r、c分别代表矩阵的行和列; 随后有r行,每行有c个整
数; 输出 输出矩阵的最大子矩阵的元素之和。
样例输入
1
4 4
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
样例输出
15
第一,如何更简单地计算出一个子矩阵的和?
先考虑子问题行数固定的矩阵(i=2,j=4)k=1~4里的矩阵哪个累加和最大,把所有的列相加得到一个一维数据,求一维数据的最大累加和。在数据录入的时候,就应该是num[i]+=num[i-1],这样,要计算从j到i的数据之和,直接num[i]-num[j-1]就能直接得出了
第二,如何求数组的最大累加和
tempmax表示当前数组以i结尾的子串的最大累加和,如果tempmax<0。说明0~i的任何一段都不可能是最大累积和的子序列。此时令tempmax=0要重新计算累加和
第三,如何遍历出所有可能的子矩阵?
这里可以使用三个变量i,j,k来遍历。如果一个矩阵大小是M*N的,那么可以使i从0到M,再使j从每一个i到M,这样就把行方向给遍历完了。再考虑列方向,直接在每一种i,j组合下,进行0到N的遍历,那么这样就等于是把所有子矩阵的情形给遍历完了。
代码如下:
public class 最大子矩阵 {
private static int num[][] = new int[101][101];
private static int n;
private static Scanner input = new Scanner(System.in);
public static void main(String[] args) {
getMax();
}
public static int getMax() {
n = input.nextInt();
n = n - 1;
while (n >= 0) {
int r, c;
r = input.nextInt();
c = input.nextInt();
int i, j, k;
initArr(r,c,num);
for (i = 1; i <= r; i++)
for (j = 1; j <= c; j++) {
num[i][j] = input.nextInt();
num[i][j] += num[i - 1][j];
}
int temp = 0;
int max = num[1][1];
int tempmax;
for (i = 1; i <= r; i++) {
for (j = i; j <= r; j++) {
tempmax = 0;
for (k = 1; k <= c; k++) {
temp = num[j][k] - num[i - 1][k];
tempmax = (tempmax >= 0 ? tempmax : 0) + temp;
max = tempmax > max ? tempmax : max;
}
}
}
System.out.println(max);
}
return 0;
}
public static void initArr(int r, int c, int[][] a) {
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
a[i][j] = 0;
}
}
}
}