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
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\n",lf); 56 return 0; 57 }
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\n",lf); 53 return 0; 54 } 55
为什么?因为放第三块布前不再需要枚举4个角,可以直接判断。递归便彻彻底底地少了一层。确实很有实际价值。不过此题WA了很久,就是因为偷懒ctrl+c却不考虑实际情况啊。