BZOJ 1052: [HAOI2007]覆盖问题
题意:给定平面上横纵坐标在-1e9~1e9内的20000个整数点的坐标,用三个大小相同边平行于坐标轴的正方形覆盖(在边界上的也算),问正方形的边长最小为多少?(整数)
思路:构造一个覆盖所有点的矩形,正方形的端点即为矩形的一角,这样枚举四个角的两个正方形,二分最大长度,看剩下的点是否能被第三个正方形覆盖。
ps:构造矩形的思想是看了题解才想到的。。。
#include<iostream> #include<cstdio> #include<cstring> #include<string.h> #include<algorithm> #include<map> #include<queue> #include<vector> #include<cmath> #include<stdlib.h> #include<time.h> using namespace std; #define rep(i,n) for((i) = 0;i < n;i++) struct Point{ int x[20200], y[20200],top; }a; const int inf = 1000000000; void cut(Point &a,int x1,int y1,int x2,int y2) { Point b; b.top = a.top; for(int k = 1;k <= a.top;k++) b.x[k] = a.x[k],b.y[k] = a.y[k]; a.top = 0; for(int i = 1;i <= b.top;i++) if(b.x[i] < x1 || b.x[i] > x2 || b.y[i] < y1 || b.y[i] > y2){ a.x[++a.top] = b.x[i]; a.y[a.top] = b.y[i]; } } void solve(Point &a,int id,int mid) { int x1 = inf ,x2 = -inf ,y1 = inf ,y2 = -inf; for(int k = 1;k <= a.top;k++){ x1 = min(x1,a.x[k]);x2 = max(x2,a.x[k]); y1 = min(y1,a.y[k]);y2 = max(y2,a.y[k]); } if(id == 1) cut(a,x1,y1,x1+mid,y1+mid); if(id == 2) cut(a,x1,y2-mid,x1+mid,y2); if(id == 3) cut(a,x2-mid,y1,x2,y1+mid); if(id == 4) cut(a,x2-mid,y2-mid,x2,y2); } bool judge(int mid) { Point b; for(int i = 1;i <= 4;i++){ for(int j = 1;j <= 4;j++){ b.top = a.top; for(int k = 1;k <= b.top;k++) b.x[k] = a.x[k],b.y[k] = a.y[k]; solve(b,i,mid); solve(b,j,mid); //可以只是一个正方形; int x1 = inf ,x2 = -inf ,y1 = inf ,y2 = -inf; for(int k = 1;k <= b.top;k++){ x1 = min(x1,b.x[k]);x2 = max(x2,b.x[k]); y1 = min(y1,b.y[k]);y2 = max(y2,b.y[k]); } if(x2 - x1 <= mid && y2 - y1 <= mid) return true; } } return false; } int main() { int n,xx,yy; cin>>n; a.top = n; for(int i = 1;i <= n;i++){ scanf("%d%d",&xx,&yy); a.x[i] = xx; a.y[i] = yy; } int l = 0,r = inf,ans; while(l <= r){ int mid = (l + r) >> 1; if(judge(mid)) ans = mid,r = mid - 1; else l = mid + 1; } printf("%d\n",ans); return 0; }