题目描述
已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵,你的任务是找到最大的非空(大小至少是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]。
输出描述:
测试数据可能有多组,对于每组测试数据,输出最大子矩阵的大小。
示例1
输入
4
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
输出
15
题目解析:将矩阵按列分开,如果相邻的矩阵列的和>0,那么加上肯定比原来的大,如果<0,比大小,留下大的。所以只用两层循环就够了,从每一行开始的得到最大矩阵,然后得出结论。
代码:
#include <stdio.h>
#include <string.h>
#define MAX(a, b) (a > b ? a : b)
#define N 105
#define INF 0x3f3f3f3f
int martix[N][N]; //存储矩阵
int buf[N]; //将相邻若干行合并成一行以后的结果
int n, maxSum; //n是矩阵大小,maxSum是最大矩阵和
// 这里就是求解最大连续子段和
int findMax() {
int i;
int result = buf[0], sum = buf[0];
for (i = 1; i < n; i++) {
if (sum <= 0) {
sum = buf[i]; //如果前面位置最大连续子序列和小于等于0,则以当前位置i结尾的最大连续子序列和为buf[i]
} else {
sum += buf[i]; //如果前面位置最大连续子序列和大于0,则以当前位置i结尾的最大连续子序列和为它们两者之和
}
result = MAX(result, sum); //更新最大连续子序列和
}
return result;
}
int main() {
int i, j, k;
while(scanf("%d", &n) != EOF) {
maxSum = -INF;
for(i = 0; i < n; i++) {
for(j = 0; j < n; j++) {
scanf("%d", &martix[i][j]);
}
}
for(i = 0; i < n; i++) { //从行开始切割矩阵
// 数组b表示j ~ n - 1行,对应列元素的和
// 将二维动态规划问题转化为一维动态规划问题
memset(buf, 0, sizeof(buf));
for(j = i; j < n; j++) {
for(k = 0; k < n; k++) {
buf[k] += martix[j][k];
}
maxSum = MAX(findMax(), maxSum);
}
}
printf("%d\n", maxSum);
}
}