问题描述
给定一个n*m的矩阵A,求A中的一个非空子矩阵,使这个子矩阵中的元素和最大。
其中,A的子矩阵指在A中行和列均连续的一块。
输入格式
输入的第一行包含两个整数n, m,分别表示矩阵A的行数和列数。
接下来n行,每行m个整数,表示矩阵A。
输出格式
输出一行,包含一个整数,表示A中最大的子矩阵中的元素和。
样例输入
3 3
-1 -4 3
3 4 -1
-5 -2 8
样例输出
10
样例说明
取最后一列,和为10。
数据规模和约定
对于50%的数据,1<=n, m<=50;
对于100%的数据,1<=n, m<=500,A中每个元素的绝对值不超过5000。
#include <iostream>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
/*
思路:类似最大子阵和,
预处理每列固定的上下界,
将二维转化为一维
*/
int main() {
int num[505][505], pre[505][505], n, m, sum, ans = -INF;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> num[i][j];
ans = max(ans, num[i][j]);
}
}
if (ans <= 0) {
cout << ans << endl;
} else {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
pre[i][j] = pre[i-1][j] + num[i][j];
// 预处理每列固定的上下界
}
}
for (int i = 1; i <= n; i++) { // 上界
for (int j = i; j <= n; j++) { // 下界
sum = 0;
for (int k = 1; k <= m; k++) { // 左右边界
if (sum + pre[j][k] - pre[i-1][k] < 0) {
// 减去pre[i-1][k]意思是减去上界之上的
sum = 0; // 预判小于0,则不考虑这块,从0再开始
} else {
sum += pre[j][k] - pre[i-1][k];
}
ans = max(ans, sum);
}
}
}
cout << ans << endl;
}
return 0;
}