洛谷P1719 最大加权矩形
一个n行n列的矩阵,找到和最大的子矩阵。
输入格式
第一行:n,接下来是n行n列的矩阵。
输出格式
最大矩形(子矩阵)的和。
输入输出样例
输入 #1
4
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
输出 #1
15
说明/提示
n<=120
最大子矩阵,一个比较容易想的思路是先算出所有前缀和。然后穷举子矩阵的两个边界点,用前缀和计算出子矩阵的元素和。这样的时间复杂度是
O
(
n
4
)
O(n^4)
O(n4)。
但其实有
O
(
n
3
)
O(n^3)
O(n3)的做法。我们穷举子矩阵的上边界,比如是第i行,接下来穷举下边界j,就从第i行穷举到最后,但注意这个遍历的同时可以把每一列的元素和叠加算出来。然后,注意到在一维上找最大子段和也是
O
(
n
)
O(n)
O(n)的,有了i到j每一列的元素和,最大子矩阵就只需要找出和最大的两列,即对应叠加结果里的最大子段和。复杂度
O
(
n
)
×
O
(
n
)
×
(
O
(
n
)
+
O
(
n
)
)
=
O
(
n
3
)
O(n)\times O(n)\times (O(n)+O(n))=O(n^3)
O(n)×O(n)×(O(n)+O(n))=O(n3)。代码如下:
- a是原矩阵,tmp存储临时子矩阵的叠加和
- dp用来计算叠加和的最大子段和
#include <iostream>
#include <limits.h>
#include <cstdio>
#include <cmath>
#include <stack>
#include <string>
#include <algorithm>
#include <sstream>
#include <vector>
#include <queue>
#include <cstring>
#include <fstream>
#include <map>
#include <list>
using namespace std;
int n,res=INT_MIN;
int a[128][128];
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++){
int tmp[128];
memset(tmp,0,sizeof(tmp));
for(int j=i;j<=n;j++){
for(int k=1;k<=n;k++) tmp[k]+=a[j][k];
int dp=0;
for(int k=1;k<=n;k++){
if(dp>0) dp=dp+tmp[k];
else dp=tmp[k];
res=max(res,dp);
}
}
}
cout<<res;
return 0;
}