最大子矩陣問題——懸線法
阿新 • • 發佈:2020-07-15
最大子矩陣問題——懸線法
最大子矩陣問題
在一個給定的矩陣中,有若干個障礙點,求出不包含障礙點的最大子矩陣。
定義
有效子矩陣
內部不包含任何障礙點且邊界與座標軸平行的子矩形。
極大有效子矩陣
一個有效子矩形,如果不存在包含它且比它大的有效子矩形,就稱這個有效子矩形為極大有效子矩形。
最大有效子矩陣
所有有效子矩形中最大的一個(或多個)。
懸線法
顧名思義,就是用一根線來回的晃動,來求出最大的子矩陣。
板子
for(int i=1;i<=n;i++){//初始化 for(int j=1;j<=m;j++){ r[i][j]=l[i][j]=j; u[i][j]=1; } } for(int i=1;i<=n;i++){//初始向左的陣列 for(int j=2;j<=m;j++){ if(滿足條件){ l[i][j]=l[i][j-1]; } } } for(int i=1;i<=n;i++){//初始向右的陣列 for(int j=m-1;j>=1;j--){ if(滿足條件){ r[i][j]=r[i][j+1]; } } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(i>1){//由上方推出狀態 if(滿足條件){ l[i][j]=max(l[i][j],l[i-1][j]); r[i][j]=min(r[i][j],r[i-1][j]); u[i][j]=u[i-1][j]+1; } } int x=r[i][j]-l[i][j]+1; int y=min(x,u[i][j]); ans=max(y,ans); } }
例題
P4147 玉蟾宮
直接將板子套上就可以了。
#include <bits/stdc++.h> using namespace std; const int maxn=1000+50; int n,m,ans; char a[maxn][maxn]; int r[maxn][maxn],l[maxn][maxn],u[maxn][maxn]; int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf(" %c ",&a[i][j]); r[i][j]=l[i][j]=j; u[i][j]=1; } } for(int i=1;i<=n;i++){ for(int j=2;j<=m;j++){ if(a[i][j]==a[i][j-1]&&a[i][j]=='F'){ 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]==a[i][j+1]&&a[i][j]=='F'){ r[i][j]=r[i][j+1]; } } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(i>1){ if(a[i][j]==a[i-1][j]&&a[i][j]=='F'){ l[i][j]=max(l[i][j],l[i-1][j]); r[i][j]=min(r[i][j],r[i-1][j]); u[i][j]=u[i-1][j]+1; } } int x=r[i][j]-l[i][j]+1; int y=min(x,u[i][j]); ans=max(x*u[i][j],ans); } } cout<<ans*3<<endl; return 0; }