悬线法 例题加解释 Luogu P1169 Luogu P4147
悬线法用于求最大面积合法子矩阵。
先上例题。
Luogu P1169 棋盘制作: https://www.luogu.org/problem/P1169
这类的问题就是明显的悬线法。
那么需要定义三个用于更新的数组。
left[i][j]表示从(i,j)这个点出发向左能到达最远的同行下标
right[i][j]表示从(i,j)这个点出发向右能到达最远的同行下标
up[i][j]表示从(i,j)这个点出发向上能到达最远的距离
那么我们就可以推出更新的方式。(伪代码)
if(满足条件){ right[i][j]=min(right[i][j],right[i-1][j]); left[i][j]=max(left[i][j],left[i-1][j]); up[i][j]=up[i-1][j]+1; }
当然也需要预处理。
首先处理所有点。
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) l[i][j]=r[i][j]=j,up[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];
那么就可以更新矩阵的答案了。
刚才例题代码如下。
#include<bits/stdc++.h> #define sc(x) scanf("%d",&x) using namespace std; int n,m,ans1,ans2; int t[2001][2001]; int l[2001][2001],r[2001][2001],u[2001][2001]; int main() { sc(n),sc(m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) sc(t[i][j]),l[i][j]=r[i][j]=j,u[i][j]=1; for(int i=1;i<=n;i++) for(int j=2;j<=m;j++) if(t[i][j]!=t[i][j-1]) l[i][j]=l[i][j-1]; for(int i=1;i<=n;i++) for(int j=m-1;j>=1;j--) if(t[i][j]!=t[i][j+1]) 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(t[i][j]!=t[i-1][j]){ u[i][j]+=u[i-1][j]; l[i][j]=max(l[i][j],l[i-1][j]); r[i][j]=min(r[i][j],r[i-1][j]); } int a=r[i][j]-l[i][j]+1; int b=min(a,u[i][j]); ans1=max(b*b,ans1); ans2=max(a*u[i][j],ans2); } cout<<ans1<<endl<<ans2<<endl; return 0; }
例题2
Luogu P4147:https://www.luogu.org/problem/P4147
也类似。用一种方式求解。
#include<bits/stdc++.h> #define sc(x) scanf("%d",&x) using namespace std; int n,m,ans1,ans2; char t[2001][2001]; int l[2001][2001],r[2001][2001],u[2001][2001]; int main() { sc(n),sc(m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%s",&t[i][j]),l[i][j]=r[i][j]=j,u[i][j]=1; for(int i=1;i<=n;i++) for(int j=2;j<=m;j++) if(t[i][j]==t[i][j-1]&&t[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(t[i][j]==t[i][j+1]&&t[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(t[i][j]==t[i-1][j]&&t[i][j]=='F'){ u[i][j]+=u[i-1][j]; l[i][j]=max(l[i][j],l[i-1][j]); r[i][j]=min(r[i][j],r[i-1][j]); } int a=r[i][j]-l[i][j]+1; int b=min(a,u[i][j]); ans1=max(b*b,ans1); ans2=max(a*u[i][j],ans2); } cout<<ans2*3<<endl; return 0; }