• BZOJ 1052 [HAOI2007]覆盖问题


    1052: [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%的数据,N<=20000


      我发现,似乎经过优化快了很多的我都会写博客。额……好吧。

      这道题在当时模拟ACM时,便已判断为二分答案O(lg n)*check O(n)。但

    是,当时并没有想到怎么去check,现在便可以说了。

      我们一共只有3张布,但所有点可以确定一个矩形,共四条边。即意味着肯定

    有布覆盖了多条边。而越界的布是没有实际意义的,所以我们可以枚举矩形的四

    个角。然后递归下去,处理干净。(贪心+DFS)

      这里有两份代码,速度有很大区别。  

     1 /**************************************************************
     2     Problem: 1052
     3     User: Doggu
     4     Language: C++
     5     Result: Accepted
     6     Time:760 ms
     7     Memory:1056 kb
     8 ****************************************************************/
     9  
    10 #include <cstdio>
    11 #include <cstring>
    12 #include <algorithm>
    13 template<class T>inline void readin(T &res) {
    14     static char ch;T flag=1;
    15     while((ch=getchar())<'0'||ch>'9')if(ch=='-')flag=-1;
    16     res=ch-48;while((ch=getchar())>='0'&&ch<='9')res=(res<<1)+(res<<3)+ch-48;res*=flag;
    17 }
    18 const int N = 20010;
    19 const int inf = 0x3f3f3f3f;
    20 struct Point {int x,y;}points[N];
    21 int n, vis[N];
    22 int DFS(int L,int siz) {
    23     if(siz==0) {
    24         for( int i = 1; i <= n; i++ ) if(!vis[i]) return 0;
    25         return 1;
    26     }
    27     int xx[2], yy[2];
    28     xx[0]=yy[0]=inf;xx[1]=yy[1]=-inf;
    29     for( int i = 1; i <= n; i++ ) if(!vis[i]) {
    30         xx[0]=std::min(xx[0],points[i].x);xx[1]=std::max(xx[1],points[i].x);
    31         yy[0]=std::min(yy[0],points[i].y);yy[1]=std::max(yy[1],points[i].y);
    32     }
    33     for( int i = 0; i <= 1; i++ ) for( int j = 0; j <= 1; j++ ) {
    34         for( int k = 1; k <= n; k++ ) if(!vis[k]&&std::max(abs(points[k].x-xx[i]),abs(points[k].y-yy[j]))<=L) vis[k]=siz;
    35         if(DFS(L,siz-1)) return 1;
    36         for( int k = 1; k <= n; k++ ) if(vis[k]==siz) vis[k]=0;
    37     }
    38     return 0;
    39 }
    40 int main() {
    41     readin(n);
    42     int mx=inf, my=inf, Mx=-inf, My=-inf;
    43     for( int i = 1; i <= n; i++ ) {
    44         readin(points[i].x), readin(points[i].y);
    45         mx=std::min(mx,points[i].x);Mx=std::max(Mx,points[i].x);
    46         my=std::min(my,points[i].y);My=std::max(My,points[i].y);
    47     }
    48     int lf=0, rg=std::max(Mx-mx,My-my);
    49     while(lf<=rg) {
    50         int mid=(lf+rg)>>1;
    51         memset(vis,0,sizeof(vis));
    52         if(!DFS(mid,3)) lf=mid+1;
    53         else rg=mid-1; 
    54     }
    55     printf("%d
    ",lf);
    56     return 0;
    57 }
    二分答案(760 ms 1056 kb)
     1 /**************************************************************
     2     Problem: 1052
     3     User: Doggu
     4     Language: C++
     5     Result: Accepted
     6     Time:348 ms
     7     Memory:1056 kb
     8 ****************************************************************/
     9  
    10 #include <cstdio>
    11 #include <cstring>
    12 #include <algorithm>
    13 template<class T>inline void readin(T &res) {
    14     static char ch;T flag=1;
    15     while((ch=getchar())<'0'||ch>'9')if(ch=='-')flag=-1;
    16     res=ch-48;while((ch=getchar())>='0'&&ch<='9')res=(res<<1)+(res<<3)+ch-48;res*=flag;
    17 }
    18 const int N = 20010;
    19 const int inf = 0x3f3f3f3f;
    20 struct Point {int x,y;}points[N];
    21 int n, vis[N];
    22 int DFS(int L,int siz) {
    23     int xx[2], yy[2];
    24     xx[0]=yy[0]=inf;xx[1]=yy[1]=-inf;
    25     for( int i = 1; i <= n; i++ ) if(!vis[i]) {
    26         xx[0]=std::min(xx[0],points[i].x);xx[1]=std::max(xx[1],points[i].x);
    27         yy[0]=std::min(yy[0],points[i].y);yy[1]=std::max(yy[1],points[i].y);
    28     }
    29     if(siz==1) return xx[1]-xx[0]<=L && yy[1]-yy[0]<=L;
    30     for( int i = 0; i <= 1; i++ ) for( int j = 0; j <= 1; j++ ) {
    31         for( int k = 1; k <= n; k++ ) if(!vis[k]&&std::max(abs(points[k].x-xx[i]),abs(points[k].y-yy[j]))<=L) vis[k]=siz;
    32         if(DFS(L,siz-1)) return 1;
    33         for( int k = 1; k <= n; k++ ) if(vis[k]==siz) vis[k]=0;
    34     }
    35     return 0;
    36 }
    37 int main() {
    38     readin(n);
    39     int mx=inf, my=inf, Mx=-inf, My=-inf;
    40     for( int i = 1; i <= n; i++ ) {
    41         readin(points[i].x), readin(points[i].y);
    42         mx=std::min(mx,points[i].x);Mx=std::max(Mx,points[i].x);
    43         my=std::min(my,points[i].y);My=std::max(My,points[i].y);
    44     }
    45     int lf=0, rg=std::max(Mx-mx,My-my);
    46     while(lf<=rg) {
    47         int mid=(lf+rg)>>1;
    48         memset(vis,0,sizeof(vis));
    49         if(!DFS(mid,3)) lf=mid+1;
    50         else rg=mid-1; 
    51     }
    52     printf("%d
    ",lf);
    53     return 0;
    54 }
    55 
    二分答案(348 ms 1056 kb)

      为什么?因为放第三块布前不再需要枚举4个角,可以直接判断。递归便彻彻底底地少了一层。确实很有实际价值。不过此题WA了很久,就是因为偷懒ctrl+c却不考虑实际情况啊。

  • 相关阅读:
    [Tool]使用ConfuserEx混淆代码
    Python_安装官方whl包和tar.gz包
    0017_集合的补充
    0016_练习题d2
    0015_各数据类型方法代码实现
    0014_基本数据类型及常用方法剖析
    0013_运算符
    0012_编码转换
    0011_练习题d1
    0010_while循环
  • 原文地址:https://www.cnblogs.com/Doggu/p/bzoj1052.html
Copyright © 2020-2023  润新知