學習筆記——懸線法


學呀學呀學呀學,學完了。

懸線法用來解決最大子矩陣問題。

嗯,就是那種DP的題。

嗯,學完了,就這些。

 

 

題目描述  Description

在一個0,1方陣中找出其中最大的全0子矩陣,所謂最大是指O的個數最多。

輸入描述  Input Description

輸入文件第一行為整數N,其中1<=N<=2000,為方陣的大小,緊接着N行每行均有N個0或1,相鄰兩數間嚴格用一個空格隔開。

輸出描述  Output Description

輸出文件僅一行包含一個整數表示要求的最大的全零子矩陣中零的個數。

樣例輸入  Sample Input

5
0 1 0 1 0
0 0 0 0 0
0 0 0 0 1
1 0 0 0 0
0 1 0 0 0

樣例輸出  Sample Output

9

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

const int N=2e3+5;

int n,ans;
int map[N];
int h[N],l[N],r[N];

inline int read()
{
    char c=getchar();int num=0;
    for(;!isdigit(c);c=getchar())
        if(c=='F')
            return 0;
        else if(c=='R')
            return 1;
    for(;isdigit(c);c=getchar())
        num=num*10+c-'0';
    return num;
}

int main()
{
    n=read();
    for(int i=1;i<=n;++i)
        l[i]=0,r[i]=n;
    for(int i=1,tmp;i<=n;++i)
    {
        tmp=1;
        for(int j=1;j<=n;++j)
        {
            map[j]=read();
            h[j]=map[j]==0?h[j]+1:0;
            tmp=map[j]?j+1:tmp;
            l[j]=map[j]==0?max(l[j],tmp):1;
        }
        tmp=n;
        for(int j=n;j;--j)
        {
            tmp=map[j]?j-1:tmp;
            r[j]=map[j]==0?min(r[j],tmp):n;
            ans=max(ans,(r[j]-l[j]+1)*h[j]);
        }
    }
    printf("%d",ans);
    return 0;
}
View Code

 

 

P4147 玉蟾宮

題目背景

有一天,小貓rainbow和freda來到了湘西張家界的天門山玉蟾宮,玉蟾宮宮主藍兔盛情地款待了它們,並賜予它們一片土地。

題目描述

這片土地被分成N*M個格子,每個格子里寫着'R'或者'F',R代表這塊土地被賜予了rainbow,F代表這塊土地被賜予了freda。

現在freda要在這里賣萌。。。它要找一塊矩形土地,要求這片土地都標着'F'並且面積最大。

但是rainbow和freda的OI水平都弱爆了,找不出這塊土地,而藍兔也想看freda賣萌(她顯然是不會編程的……),所以它們決定,如果你找到的土地面積為S,它們每人給你S兩銀子。

輸入輸出格式

輸入格式:

 

第一行兩個整數N,M,表示矩形土地有N行M列。

接下來N行,每行M個用空格隔開的字符'F'或'R',描述了矩形土地。

 

輸出格式:

 

輸出一個整數,表示你能得到多少銀子,即(3*最大'F'矩形土地面積)的值。

 

輸入輸出樣例

輸入樣例#1:  復制
5 6 
R F F F F F 
F F F F F F 
R R R F F F 
F F F F F F 
F F F F F F
輸出樣例#1:  復制
45

說明

對於50%的數據,1<=N,M<=200

對於100%的數據,1<=N,M<=1000

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

const int N=2e3+5;

int n,m,ans;
int map[N];
int h[N],l[N],r[N];

inline int read()
{
    char c=getchar();int num=0;
    for(;!isdigit(c);c=getchar())
        if(c=='F')
            return 0;
        else if(c=='R')
            return 1;
    for(;isdigit(c);c=getchar())
        num=num*10+c-'0';
    return num;
}

int main()
{
    n=read(),m=read();
    for(int i=1;i<=m;++i)
        l[i]=0,r[i]=m;
    for(int i=1,tmp;i<=n;++i)
    {
        tmp=1;
        for(int j=1;j<=m;++j)
        {
            map[j]=read();
            h[j]=map[j]==0?h[j]+1:0;
            tmp=map[j]?j+1:tmp;
            l[j]=map[j]==0?max(l[j],tmp):1;
        }
        tmp=m;
        for(int j=m;j;--j)
        {
            tmp=map[j]?j-1:tmp;
            r[j]=map[j]==0?min(r[j],tmp):m;
            ans=max(ans,(r[j]-l[j]+1)*h[j]);
        }
    }
    printf("%d",ans*3);
    return 0;
}
View Code

 

 

P1578 奶牛浴場

題目描述

由於John建造了牛場圍欄,激起了奶牛的憤怒,奶牛的產奶量急劇減少。為了討好奶牛,John決定在牛場中建造一個大型浴場。但是John的奶牛有一個奇怪的習慣,每頭奶牛都必須在牛場中的一個固定的位置產奶,而奶牛顯然不能在浴場中產奶,於是,John希望所建造的浴場不覆蓋這些產奶點。這回,他又要求助於Clevow了。你還能幫助Clevow嗎?

John的牛場和規划的浴場都是矩形。浴場要完全位於牛場之內,並且浴場的輪廓要與牛場的輪廓平行或者重合。浴場不能覆蓋任何產奶點,但是產奶點可以位於浴場的輪廓上。

Clevow當然希望浴場的面積盡可能大了,所以你的任務就是幫她計算浴場的最大面積。

輸入輸出格式

輸入格式:

 

輸入文件的第一行包含兩個整數L和W,分別表示牛場的長和寬。文件的第二行包含一個整數n,表示產奶點的數量。以下n行每行包含兩個整數x和y,表示一個產奶點的坐標。所有產奶點都位於牛場內,即:0<=x<=L,0<=y<=W。

 

輸出格式:

 

輸出文件僅一行,包含一個整數S,表示浴場的最大面積。

 

輸入輸出樣例

輸入樣例#1:  復制
10 10
4
1 1
9 1
1 9
9 9
輸出樣例#1:  復制
80

說明

0<=n<=5000

1<=L,W<=30000

Winter Camp 2002

 

//懸線法學習練習
//並非懸線法的做法
//懸線法pre 
//復雜度 O(障礙數的個數^2)
//還是挺優秀的 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

const int N=3e4+5;

int n,m,s;
int ans;
struct OBS
{
    int x,y;
}obs[N];

inline int read()
{
    char c=getchar();int num=0;
    for(;!isdigit(c);c=getchar());
    for(;isdigit(c);c=getchar())
        num=num*10+c-'0';
    return num;
}

bool cmp1(const OBS &a,const OBS &b)
{
    return a.y<b.y;
}

bool cmp2(const OBS &a,const OBS &b)
{
    return a.x<b.x;
}

int main()
{
    n=read(),m=read();
    s=read();
    for(int i=1;i<=s;++i)
        obs[i].x=read(),obs[i].y=read();
    obs[++s].x=0,obs[s].y=0;
    obs[++s].x=n,obs[s].y=0;
    obs[++s].x=0,obs[s].y=m;
    obs[++s].x=n,obs[s].y=m;
    sort(obs+1,obs+s+1,cmp1);
    for(int i=1,L,H,cei,flo,len;i<=s;++i)
    {
        H=obs[i].x,L=obs[i].y,len=m-L;
        cei=0,flo=n;
        for(int j=i+1;j<=s;++j)
        {
            if(len*(flo-cei)<=ans)
                break;
            if(obs[j].x<cei||obs[j].x>flo)
                continue;
            ans=max(ans,(obs[j].y-L)*(flo-cei));
            if(obs[j].x==H)
                break;
            else if(obs[j].x<H)
                cei=obs[j].x;
            else
                flo=obs[j].x;
        }
    }
    for(int i=m,R,H,cei,flo,len;i;--i)
    {
        H=obs[i].x,R=obs[i].y,len=R;
        cei=0,flo=n;
        for(int j=i-1;j;--j)
        {
            if(len*(flo-cei)<=ans)
                break;
            if(obs[j].x<cei||obs[j].x>flo)
                continue;
            ans=max(ans,(R-obs[j].y)*(flo-cei));
            if(obs[j].x==H)
                break;
            else if(obs[j].x<H)
                cei=obs[j].x;
            else
                flo=obs[j].x;
        }
    }
    sort(obs+1,obs+s+1,cmp2);
    for(int i=1;i<s;++i)
    {
//        printf("%d %d\n",obs[i+1].x,obs[i].x);
        ans=max(ans,(obs[i+1].x-obs[i].x)*m);
    }
    printf("%d",ans);
    return 0;
}
不是懸線法 懸線法pre

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM