BZOJ1052: [HAOI2007]覆盖问题

Description
某人在山上种了N棵小树苗。冬天来了,温度急速下降,小树苗脆弱得不堪一击,于是树主人想用一些塑料薄膜把这些小树遮盖起来,经过一番长久的思考,他决定用3个L*L的正方形塑料薄膜将小树遮起来。我们不妨将山建立一个平面直角坐标系,设第i棵小树的坐标为(Xi,Yi),3个L*L的正方形的边要求平行与坐标轴,一个点如果在正方形的边界上,也算作被覆盖。当然,我们希望塑料薄膜面积越小越好,即求L最小值。
Input
第一行有一个正整数N,表示有多少棵树。接下来有N行,第i+1行有2个整数Xi,Yi,表示第i棵树的坐标,保证不会有2个树的坐标相同。
Output
一行,输出最小的L值。
Sample Input
4
0 1
0 -1
1 0
-1 0
Sample Output
1
HINT
100%的数据,-1,000,000,000<=Xi,Yi<=1,000,000,000
100%的数据,N<=20000
Source

答案满足单调性,所以直接二分答案。判定放薄膜的时候,显然最优方案就是薄膜的四角中的某一角在一棵树上(可以枚举),如果放了两次以后,薄膜能覆盖相距最远的两棵树,即返回1。

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cctype>
#define INF 1000000000
using namespace std;
const int N=20010;
struct data{int x[N],y[N],n;}map;
void in(int &x)
{
    x=0;int f=1;char t=getchar();
    while(!isdigit(t)){if(t=='-')f=-1;t=getchar();}
    while(isdigit(t)){x=x*10+t-48;t=getchar();}
    x*=f;
}
void chuli(data &a,int x1,int y1,int x2,int y2)
{
    int now=0;
    for (int i=1;i<=a.n;++i)
    if ((a.x[i]<x1)or(a.x[i]>x2)or(a.y[i]<y1)or(a.y[i]>y2))
    {
        ++now;
        a.x[now]=a.x[i];
        a.y[now]=a.y[i];
    }
    a.n=now;
}
void work(data &a,int flag,int x)
{
    int x1=INF,y1=INF,x2=-INF,y2=-INF;
    for (int i=1;i<=a.n;++i)
    {
        x1=min(x1,a.x[i]);y1=min(y1,a.y[i]);
        x2=max(x2,a.x[i]);y2=max(y2,a.y[i]);
    }
    if (flag==1) chuli(a,x1,y1,x1+x,y1+x);
    if (flag==2) chuli(a,x2-x,y1,x2,y1+x);
    if (flag==3) chuli(a,x1,y2-x,x1+x,y2);
    if (flag==4) chuli(a,x2-x,y2-x,x2,y2);
}
bool can(int l)
{
    for (int x=1;x<=4;++x)
        for (int y=1;y<=4;++y)
        {
            data tmp;tmp.n=map.n;
            for (int i=1;i<=tmp.n;++i)
            tmp.x[i]=map.x[i],tmp.y[i]=map.y[i];
            work(tmp,x,l);//第一次
            work(tmp,y,l);//第二次
            if (tmp.n==0) return 1;
            int x1=INF,y1=INF,x2=-INF,y2=-INF;
            for (int i=1;i<=tmp.n;++i)
            {
                x1=min(x1,tmp.x[i]);y1=min(y1,tmp.y[i]);
                x2=max(x2,tmp.x[i]);y2=max(y2,tmp.y[i]);
            }
            if ((x2-x1<=l)and(y2-y1<=l)) return 1;
        }
    return 0;
}
int main()
{
    in(map.n);
    for (int i=1;i<=map.n;++i)
    in(map.x[i]),in(map.y[i]);
    int head=1,tail=INF;
    while(head<tail)
    {
        int mid=(head+tail)>>1;
        if (can(mid)) tail=mid;
        else head=mid+1;
    }
    printf("%d",head);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值