bzoj 1052: [HAOI2007]覆盖问题

Description
某人在山上种了N棵小树苗。冬天来了,温度急速下降,小树苗脆弱得不堪一击,于是树主人想用一些塑料薄
膜把这些小树遮盖起来,经过一番长久的思考,他决定用3个LL的正方形塑料薄膜将小树遮起来。我们不妨将山建
立一个平面直角坐标系,设第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

解题报告:

这题明显的二分答案,至于怎么check,需要想一下,朴素的我们会选择从按x轴左到右扫一遍,然后没有被覆盖的就以该点为正方形的左边,选择能覆盖的点最多的去覆盖,这样处理起来复杂度不对且实现很难,那么考虑贪心,每次找出能覆盖所有的点最小矩形,然后搜索四个角,选择一个去覆盖剩余点,然后不断递归,如果最后层数小于3就符合要求.其实思路和这个差不多,因为矩形一定是卡在点上的,相当于以该点为正方形的某个边,然后尽量多的覆盖点

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
using namespace std;
const int N=30005,inf=2e8;
int x[N],y[N],n;int vis[N];
void updata(int &xl,int &yl,int &xr,int &yr){
    xl=yl=inf;xr=yr=-inf;
    for(int i=1;i<=n;i++){
        if(vis[i])continue;
        xl=Min(xl,x[i]);yl=Min(yl,y[i]);
        xr=Max(xr,x[i]);yr=Max(yr,y[i]);
    }
}
void upd(int xl,int yl,int xr,int yr,int col){
    for(int i=1;i<=n;i++){
        if(!vis[i] && x[i]>=xl && x[i]<=xr && y[i]>=yl && y[i]<=yr)
            vis[i]=col;
    }
}
bool dfs(int dep,int mid){
    int X[3],Y[3];
    updata(X[1],Y[1],X[2],Y[2]);
    if(Max(X[2]-X[1],Y[2]-Y[1])<=mid)return true;
    if(dep==3)return false;
    for(int i=1;i<=2;i++){
        for(int j=1;j<=2;j++){
            if(i==1){
                if(j==1)upd(X[i],Y[j],X[i]+mid,Y[j]+mid,dep);
                else upd(X[i],Y[j]-mid,X[i]+mid,Y[j],dep);
            }
            else{
                if(j==1)upd(X[i]-mid,Y[j],X[i],Y[j]+mid,dep);
                else upd(X[i]-mid,Y[j]-mid,X[i],Y[j],dep);
            }
            if(dfs(dep+1,mid))return true;
            for(int k=1;k<=n;k++)
                if(vis[k]==dep)vis[k]=false;
        }
    }
    return false;
}
bool check(int mid){
    memset(vis,0,sizeof(vis));
    return dfs(1,mid);
}
void work()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&x[i],&y[i]);
    }
    int l=1,r=2e9,mid,ans=-1;
    while(l<=r){
        mid=(l+r)>>1;
        if(check(mid))ans=mid,r=mid-1;
        else l=mid+1;
    }
    printf("%d\n",ans);
}

int main()
{
    work();
    return 0;
}
posted @ 2017-08-26 14:51  PIPIBoss  阅读(281)  评论(0编辑  收藏  举报