1. 程式人生 > >懸線法學習筆記

懸線法學習筆記

zjoi2007 懸線法 main zjoi 制作 cin efi space fin

懸線法:一般求最大子矩形

懸線法,懸線的定義,就是一條豎線,這條豎線要滿足上端點在整個矩形上邊界或者是一個障礙點。然後以這條懸線進行左右移動,直到移至障礙點或者是矩陣邊界,進而確定這條懸線所在的極大矩陣。

所以我們需要\(Left[]\)數組存每個點能到達的最右位置,\(Right[]\)數組存放每個點能到達的最左位置,\(Up[]\)數組位置。

設置好這些數組之後,我們開始遍歷矩陣中的每個點,把每個點和上一個點的\(Left\)\(Right\)進行比較,分別取最大和最小,Up則是上一個點的Up+1,進而求出面積進行比較。

經典例題:
ZJOI2007 棋盤制作

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define MAXN 2010
using namespace std;
int l[MAXN][MAXN],r[MAXN][MAXN],up[MAXN][MAXN],a[MAXN][MAXN];
int n,m,ans1,ans2;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&a[i][j]),l[i][j]=j,r[i][j]=j,up[i][j]=1;
    for(int i=1;i<=n;i++)
        for(int j=2;j<=m;j++)
            if(a[i][j]==1-a[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(a[i][j]==1-a[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&&a[i][j]==1-a[i-1][j])
            {
                up[i][j]=up[i-1][j]+1;
                l[i][j]=max(l[i-1][j],l[i][j]);
                r[i][j]=min(r[i-1][j],r[i][j]);
            }
            int kuan=r[i][j]-l[i][j]+1;
            int square=min(kuan,up[i][j]);
            ans1=max(ans1,square*square);
            ans2=max(ans2,kuan*up[i][j]);
        }
    }
    printf("%d\n%d\n",ans1,ans2);
    return 0;
} 

luogu 玉蟾宮

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define MAXN 2010
using namespace std;
int l[MAXN][MAXN],r[MAXN][MAXN],up[MAXN][MAXN];
char a[MAXN][MAXN];
int n,m,ans1,ans2;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>a[i][j],l[i][j]=j,r[i][j]=j,up[i][j]=1;
    for(int i=1;i<=n;i++)
        for(int j=2;j<=m;j++)
            if(a[i][j]=='F'&&a[i][j-1]=='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]=='F'&&a[i][j+1]=='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&&a[i][j]=='F'&&a[i-1][j]=='F')
            {
                up[i][j]=up[i-1][j]+1;
                l[i][j]=max(l[i-1][j],l[i][j]);
                r[i][j]=min(r[i-1][j],r[i][j]);
            }
            int kuan=r[i][j]-l[i][j]+1;
            ans2=max(ans2,kuan*up[i][j]);
        }
    }
    printf("%d\n",3*ans2);
    return 0;
} 

懸線法學習筆記