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