悬线法 例题加解释 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;
}
原文地址:https://www.cnblogs.com/ChrisKKK/p/11260741.html