bzoj1052 二分+贪心

某人在山上种了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


hzwer的o(n)也是orz了…
其实思路还是蛮简单的,我们先用一个最小矩形框住这些点,因为只有三个正方形,然而有四个角,显然角落上必然有一个,然而挖掉一个正方形以后用剩下的点再框的矩形里同理也有一个正方形在角落上.
我们二分,贪心check,先暴力枚举四个角挖掉两个正方形,再将剩下的点集构成的最小矩形,判断一下是否都小于mid,check枚举中一直找到这样的允许的情况为止.否则false;

#include<stdio.h>
#include<algorithm>
const int maxn=20001;
const int inf=1000000000;
int ans,cnt,lf,rg,mid,n;
inline const int read(){
    register int f=1,x=0;
    register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return f*x;
}
struct data{
    int x[maxn],y[maxn],top;
}a,b;
inline void erase(data &a,int x1,int y1,int x2,int y2){
    cnt=0;
    for(int i=1;i<=a.top;i++)
      if(a.x[i]<x1||a.x[i]>x2||a.y[i]<y1||a.y[i]>y2) 
        cnt++,a.x[cnt]=a.x[i],a.y[cnt]=a.y[i];
    a.top=cnt;
}
inline void calc(data &a,int opt){
    int x1=inf,x2=-inf,y1=inf,y2=-inf;
    for(int i=1;i<=a.top;i++){
        x1=std::min(x1,a.x[i]),x2=std::max(x2,a.x[i]);
        y1=std::min(y1,a.y[i]),y2=std::max(y2,a.y[i]);
    }
    if(opt==1) erase(a,x1,y1,x1+mid,y1+mid); 
    if(opt==2) erase(a,x2-mid,y1,x2,y1+mid);
    if(opt==3) erase(a,x1,y2-mid,x1+mid,y2);
    if(opt==4) erase(a,x2-mid,y2-mid,x2,y2);
}
inline bool check(){
    data b;
    for(int x=1;x<=4;x++)
     for(int y=1;y<=4;y++){
         b.top=a.top;
         for(int i=1;i<=b.top;i++) b.x[i]=a.x[i],b.y[i]=a.y[i];
         calc(b,x),calc(b,y);
         int x1=inf,x2=-inf,y1=inf,y2=-inf;
         for(int i=1;i<=b.top;i++){
             x1=std::min(x1,b.x[i]),x2=std::max(x2,b.x[i]);
             y1=std::min(y1,b.y[i]),y2=std::max(y2,b.y[i]);
         }
         if(x2-x1<=mid&&y2-y1<=mid) return true;
     } 
     return false;
}
int main(){
    n=read(),a.top=n;
    for(register int i=1;i<=n;i++) a.x[i]=read(),a.y[i]=read();
    lf=1,rg=inf;
    while(lf<=rg){
       mid=(lf+rg)>>1;
       if(check()) ans=mid,rg=mid-1;
       else lf=mid+1;
    }
    printf("%d\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值