洛谷P4147 玉蟾宮
阿新 • • 發佈:2020-12-12
題面
給定一個\(n*m\)的\(0/1\)矩陣,求最大子矩陣:滿足矩陣內所有元素均為\(1\).
輸出矩陣大小\(*3\)
分析
懸線法,最大子矩陣板子題
(也可以單調棧和並查集,但是窩不會)
維護三個值\(l[i][j]\)和\(r[i][j],up[i][j]\),分別代表當前點\((i,j)\)向左最長的延伸到的點位置,向右最長的延伸到的點位置,向上最長的延伸長度
(我們稱當前點和其左右相鄰的點都是\(1\)的話就可以延伸。也就是說,如果當前點\(a[i][j]==1\),那麼這個點就非法)
所以我們可以直接列舉\(i,j\)找到這個矩陣就行了/fad
具體實現看程式碼
程式碼
#include<bits/stdc++.h> using namespace std; template <typename T> inline void read(T &x){ x=0;char ch=getchar();bool f=false; while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x=f?-x:x; return ; } template <typename T> inline void write(T x){ if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10^48); return ; } const int N=1005; int n,m; int a[N][N],l[N][N],r[N][N],up[N][N],ans; char op[2]; int main(){ read(n),read(m); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%s",op); if(op[0]=='F') a[i][j]=1; up[i][j]=1; l[i][j]=r[i][j]=j; } } for(int i=1;i<=n;i++){ for(int j=2;j<=m;j++){ if(a[i][j]==1&&a[i][j-1]==1) l[i][j]=l[i][j-1]; } } for(int i=1;i<=n;i++){ for(int j=m-1;j>=1;j--){ if(a[i][j]==1&&a[i][j+1]==1) r[i][j]=r[i][j+1]; } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(!a[i][j]) continue; if(i>1&&a[i][j]==1&&a[i-1][j]==1){ r[i][j]=min(r[i][j],r[i-1][j]); l[i][j]=max(l[i][j],l[i-1][j]); up[i][j]=up[i-1][j]+1; } ans=max(ans,(r[i][j]-l[i][j]+1)*up[i][j]); } } write(ans*3); return 0; }