题目
给定一个包含整数的二维矩阵,子矩形是位于整个阵列内的任何大小为1 * 1或更大的连续子阵列。
矩形的总和是该矩形中所有元素的总和。
在这个问题中,具有最大和的子矩形被称为最大子矩形。
输入格式
输入中将包含一个N*N的整数数组。
第一行只输入一个整数N,表示方形二维数组的大小。
从第二行开始,输入N*N的矩阵。
数组中的数字会保持在[-127,127]的范围内。
输出格式
输出一个整数,代表最大子矩形的总和。
数据范围
1≤N≤100
输入样例
4
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
输出样例
15
分析:
- 看到题目,我们第一种想法就是暴力枚举,矩阵的左上角的点和右下角的点,
然后用前缀和来求解枚举矩阵的值,但是这样时间复杂度是O(n^4)。显然会超时。 - 因此我们应该需要简化,我们先考虑一维,即第一行:
0 -2 -7 0
- 就相当于求他的最大子段,我们可以用dp求
dp[i]=max(dp[i],dp[i-1]+a[i]);
- 可以得到最大字段和为0;
- 然后我们再考虑第一行和第二行;
0 -2 -7 0
9 2 -6 2
- 我们可以将第二行的值全部加到第一行,这样我们就发现,这又是求一次最大子段和:
9 0 -13 2
- 所以他的第一行和第二行最大值矩阵值为9
- 就这样我们可以枚举他的首行和尾行,然后再将值全部加到一行,对他求一次最大字段和,然后取每次枚举的最大值,就是我们的答案,这样时间复杂度就会降到O(n^3)。
代码:
#include <bits/stdc++.h>
using namespace std;
int n,x,a[125][125],temp[125],dp[125],ans=-0x3f3f3f3f;
void arrsum(){ // 求temp数组的最大字段和
for(int i=1;i<=n;i++) dp[i]=temp[i];
for(int i=1;i<=n;i++){
dp[i]=max(dp[i],dp[i-1]+temp[i]);
ans=max(ans,dp[i]);
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
}
}
for(int i=1;i<=n;i++){ //枚举首行
memset(temp,0,sizeof(temp));
for(int j=i;j<=n;j++){
for(int k=1;k<=n;k++){//加上每行的值
temp[k]=temp[k]+a[j][k];
}
arrsum();//每加上一行计算一次字段和
}
}
cout<<ans<<endl;
return 0;
}