题意:给定n*m的网格,求每一列都为不下降序列的最大子矩阵的大小。
思路:借这个题学习了一下悬线法,悬线法顾名思义,等于一个节点,先计算该点的上边界,就像一条竖线,然后计算每条竖线的左边界和右边界,看他最多能扫过的面积就是我们要求的最大子矩阵的面积。
代码:
#include <bits/stdc++.h>
using namespace std;
int a[2010];
int h[2010][2010],l[2010][2010],r[2010][2010];
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int _;
cin>>_;
while(_--){
memset(a,0,sizeof(a));
memset(h,0,sizeof(h));
memset(l,0,sizeof(l));
memset(r,0,sizeof(r));
int n,m,x;
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
cin>>x;
if(x>=a[j]) h[i][j]=h[i-1][j]+1;
else h[i][j]=1;
a[j]=x;
l[i][j]=r[i][j]=j; //初始化左右边界
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
//计算i,j的左边界最远能到达哪一列
while(l[i][j]>1&&h[i][j]<=h[i][l[i][j]-1]){
l[i][j]=l[i][l[i][j]-1];
}
}
for(int j=m;j>=1;j--){
//计算i,j的右边界最远能到达哪一列
while(r[i][j]<m&&h[i][j]<=h[i][r[i][j]+1]){
r[i][j]=r[i][r[i][j]+1];
}
}
}
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
ans=max(ans,h[i][j]*(r[i][j]-l[i][j]+1));
}
}
cout<<ans<<"\n";
}
return 0;
}