题目描述
已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵,你的任务是找到最大的非空(大小至少是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)
再后面的若干行中,依次给出矩阵中的N2个整数,整数之间由空白字符分隔(空格或者空行)。
已知矩阵中整数的范围都在[-127, 127]。
输出:
测试数据可能有多组,对于每组测试数据,输出最大子矩阵的大小。
样例输入
1
27
3
-40 29 -16
38 18 22
24 -35 5
样例输出
27
78
思路
基本思路,先按行计算列加和的最大序列和,最后输出这些最大序列和中最大的一个。
举个栗子,例如一个5*5的矩阵,已知最大子矩阵左上角元素是第0行第0列,右下角元素是第2行第1列,这个最大子矩阵的和怎么计算呢?可以这样计算,先将原始矩阵第0行到第2行所有元素按列加和,这样就把一个3*5的矩阵转化为了1*5的矩阵,对这个1*5矩阵求最大序列和就是这个最大子矩阵的和。
有了以上思路,我们可以这样分解问题,最大子矩阵一定在第i行到第j行之间,所以分别计算第0行到第0行,第0行到第1行,第0行到第2行…第1行到第1行,第1行到第1行…第n-1行到第n-1行的列加和,然后分别计算这些形成的一维矩阵的最大序列和,这些最大序列和中最大的一个就是答案。
总结,先按行将二维矩阵转化为一维列加和数组,然后计算这些数组的最大序列和,这些最大序列和中最大的一个就是最大子矩阵的和。
代码
#include <iostream>
#include <cstring>
using namespace std;
int main(){
int n;
while(cin>>n){
int matrix[n][n],sum[n],dp[n],maxSum;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>matrix[i][j];
maxSum=matrix[0][0];
for(int i=0;i<n;i++){
memset(sum,0,sizeof(sum));
for(int j=i;j<n;j++){
for(int k=0;k<n;k++)
sum[k]+=matrix[j][k];
dp[0]=sum[0];
maxSum=max(dp[0],maxSum);
for(int k=1;k<n;k++){
dp[k]=max(sum[k],dp[k-1]+sum[k]);
maxSum=max(dp[k],maxSum);
}
}
}
cout<<maxSum<<endl;
}
return 0;
}