[POJ 1050]To the Max

 给出一个数字矩阵,求子矩阵数字之和的最大值.这是最大子段和问题.(该题的AC代码

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

int n, a;
long long sum, ans = -100000000;

int main(){
    cin >> n;
    for(int i = 0; i < n; i++){
        cin >> a;
        sum += a;
        ans = max(ans, sum);
        if(sum < 0) sum = 0;
    }
    cout << ans << endl;

    return 0;
}
View Code

,注意输入全为负数的情况)

上述一维情况本质上是在枚举和剪枝,可以通过简单的单层循环实现,发现和为负数时舍弃当前子段.

而二维情况下,没有办法这样"线性"枚举,想要舍弃时也有所顾虑.

由于数据比较小(n <= 100),直接暴力枚举子矩阵的左上角坐标(x1,y1)和右下角坐标(y1,y2)求解.O(n4)(粗略的)也不会爆.因为右下角坐标总是在左上角坐标之右下.

如何计算子矩阵数字之和?不用前缀和的话复杂度会变成O(n6).

从坐标(x1+1,y1+1)到(x2,y2)的所有数字之和即为:

s[x2][y2] + s[x1][y1] - s[x2][y1] - s[x1][y2]

由于矩阵是按从左上到右下的顺序给出的,前缀和在读入时就可以计算了.

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

int n, s[110][110], ans = -100000000;    // 同样要考虑全为负数情况

int main(){
    cin >> n;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++){
            cin >> s[i][j];
            s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
        }

    for(int x1 = 0; x1 <= n - 1; x1++)
        for(int y1 = 0; y1 <= n - 1; y1++)
            for(int x2 = x1 + 1; x2 <= n; x2++)
                for(int y2 = y1 + 1; y2 <= n; y2++)
                    ans = max(ans, s[x2][y2] + s[x1][y1] - s[x2][y1] - s[x1][y2]);
    cout << ans << endl;

    return 0;
}
posted @ 2020-12-17 10:08  goverclock  阅读(105)  评论(1编辑  收藏  举报