求只有0和1的矩阵中第二大的全1子矩阵的1的个数
题解:单调栈求最大子矩阵 与这道题一样(板子)https://www.cnblogs.com/Kv-Stalin/p/9164705.html(特别详细),唯一不同就是最后要求的结果不同,所以有了代码中的去重部分,因为在处理每一行通过单调栈算矩形面积时,会重复算一个矩形面积好多次放在优先队列里,为避免这个才有了去重部分。
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<stdlib.h>
#include<stack>
#include<queue>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1005;
int a[maxn][maxn];
int c[maxn][maxn];
int maxx,cnt;
int n,m;
int fun(int x,int y){
if(x>n) return 0;
if(c[x][y]==1){
a[x][y]=1;
}
fun(x+1,y);
if(a[x][y])
a[x][y]+=a[x+1][y];
return a[x][y];
}
int l[maxn];
int r[maxn];
priority_queue<int>q;
void gofun(int x){
stack<int> s;
for(int i=0;i<1005;i++)
l[i]=r[i]=0;
while(!s.empty()) s.pop();
for(int i=1;i<=m;i++){//单增栈 找左边第一个小于的数
while(!s.empty()&&a[x][s.top()]>=a[x][i]) s.pop();
if(s.empty()) l[i]=1;
else l[i]=s.top()+1;
s.push(i);
}
while(!s.empty()) s.pop();
for(int i=m;i>=1;i--){//找右边第一个小于的数 从后往前找 依旧单增栈
while(!s.empty()&&a[x][s.top()]>=a[x][i]) s.pop();
if(s.empty()) r[i]=m;
else r[i]=s.top()-1;
s.push(i);
}
for(int i=1;i<=m;i++){
int area=a[x][i]*(r[i]-l[i]+1);
if(area>maxx){//去重
cnt=0;
maxx=area;
for(int j=l[i];j<=r[i];j++){//遍历同底
if(a[x][i]==a[x][j])//找同高
cnt++;
}
}
q.push(area);
q.push(max(a[x][i]*(r[i]-l[i]),(a[x][i]-1)*(r[i]-l[i]+1)));
//这里直接把每个矩形的去掉一列或去掉一行的矩形面积算出来放优先队列
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char ch;
cin>>ch;
if(ch=='1') c[i][j]=1;
else c[i][j]=0;
}
}
for(int i=1;i<=m;i++){
fun(1,i);
}
for(int i=1;i<=n;i++){
gofun(i);
}
while(!q.empty()){
q.pop();
cnt--;
if(cnt==0) break;
}
if(!q.empty()) cout<<q.top()<<endl;
else cout<<0<<endl;
return 0;
}