题目描述

已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵,你的任务是找到最大的非空(大小至少是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

时间复杂度

O(n4)

思路

本题输入规模最大100,用动态规划可以做到O(n3)。下面暴力思路是O(n4),但是思路简单,代码简单。
枚举矩阵中每两两个坐标,用前缀和优化求子矩阵的过程。只要给出两个左上角,和右上角的坐标,就能求子矩阵。
求和:s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + a[i][j];
求子矩阵(a,b,c,d): = s[c][d] - s[a-1][d] - s[c][b-1] + s[a-1][b-1];

代码

#include <iostream>
using namespace std;
const int N = 101;
int sum[N][N];
int n;
void get(int x,int y,int &max)//左上角是(x,y),右下角是(i,j)
{
    for(int i = x; i <= n; i ++)
    {
        for(int j = y +1 ; j <=n ; j++)
        {
            int t = sum[i][j] - sum[x-1][j]  - sum[i][y-1] + sum[x-1][y-1];
            //cout<< t <<endl;
            if(t > max){
                max = t;
            }
        }
    }
}
int main()
{

    while(cin>>n)
    {
        for(int i = 1; i <=n ; i++)
        {
            for(int j = 1; j <= n ; j++)
            {
                int t; cin>>t;
                sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + t;
            }
        }
        int max = 0x80000001;
        for(int i = 1; i <= n ; i++)
        {
            for(int j = 1; j <= n ; j ++)
            {
                get(i,j,max);
            }
        }
        cout<<max<<endl;
    }
}