学习笔记——悬线法

学呀学呀学呀学,学完了。

悬线法用来解决最大子矩阵问题。

嗯,就是那种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

 

posted @ 2018-04-29 21:54  whymhe  阅读(1854)  评论(0编辑  收藏  举报