题目描述
某人在山上种了N棵小树苗。冬天来了,温度急速下降,小树苗脆弱得不堪一击,于是树主人想用一些塑料薄膜把这些小树遮盖起来,经过一番长久的思考,他决定 用3个L*L的正方形塑料薄膜将小树遮起来。我们不妨将山建立一个平面直角坐标系,设第i棵小树的坐标为(Xi,Yi),3个L*L的正方形的边要求平行 与坐标轴,一个点如果在正方形的边界上,也算作被覆盖。当然,我们希望塑料薄膜面积越小越好,即求L最小值。
输入输出格式
输入格式:
第一行有一个正整数N,表示有多少棵树。
接下来有N行,第i+1行有2个整数Xi,Yi,表示第i棵树的坐标,保证不会有2个树的坐标相同。
输出格式:
一行,输出最小的L值。
输入输出样例
说明
数据范围
100%的数据,-1,000,000,000<=Xi,Yi<=1,000,000,000
30%的数据,N<=100
50%的数据,N<=2000
100%的数据,N<=20000
这么细节的题居然1A了,感觉手感回来了呀。
题目指名道姓用3个正方形覆盖肯定是有操作的。考虑最靠左的点,最靠上的点,最靠下的点,最靠右的点,有4个,那么其中的两个肯定要被同一个正方形覆盖,而且显然覆盖的最优策略是直接卡在边界上。那么我们直接枚举一次性覆盖哪两个点,将问题转化为用两个正方形去覆盖剩下的点,发现不是一个左上一个右下就是一个左下一个右上。就可以在很大很大常数的O(n log n)内解决这道题。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 2e4 + 5;
const int inf = 0x3f3f3f3f;
struct Point {
int pos[2];
} pt[maxn];
int mn[2], mx[2], nmn[2], nmx[2], n, vis[maxn];
bool in(const int &x, const int &y, const int &L, const int *pos) {
return pos[0] <= x + L && pos[0] >= x && pos[1] <= y + L && pos[1] >= y;
}
void del(const int &x, const int &y, const int &L, int & cover) {
for(register int i = 1; i <= n; ++i)
if(in(x, y, L, pt[i].pos))
if(!vis[i]) vis[i] = 1, ++cover;
}
void rewM(int * mn, int * mx) {
mn[0] = mn[1] = inf;
mx[0] = mx[1] = -inf;
for(register int i = 1; i <= n; ++i) {
if(vis[i]) continue;
mn[0] = min(pt[i].pos[0], mn[0]);
mn[1] = min(pt[i].pos[1], mn[1]);
mx[0] = max(pt[i].pos[0], mx[0]);
mx[1] = max(pt[i].pos[1], mx[1]);
}
}
bool check2(int x, int y, int L) {
int cover = 0;
memset(vis, 0, sizeof(vis));
del(x, y, L, cover);
rewM(mn, mx);
if(cover == n) return 1;
del(mn[0], mn[1], L, cover);
if(cover == n) return 1;
del(mx[0] - L, mx[1] - L, L, cover);
return cover == n;
}
bool check3(int x, int y, int L) {
int cover = 0;
memset(vis, 0, sizeof(vis));
del(x, y, L, cover);
rewM(mn, mx);
if(cover == n) return 1;
del(mn[0], mx[1] - L, L, cover);
if(cover == n) return 1;
del(mx[0] - L, mn[1], L, cover);
return cover == n;
}
bool check(int L) {
if(check2(nmn[0], nmn[1], L) || check3(nmn[0], nmn[1], L)) return true;
if(check2(nmn[0], nmx[1] - L, L) || check3(nmn[0], nmx[1] - L, L)) return true;
if(check2(nmx[0] - L, nmn[1], L) || check3(nmx[0] - L, nmn[1], L)) return true;
if(check2(nmx[0] - L, nmx[1] - L, L) || check3(nmx[0] - L, nmx[1] - L, L)) return true;
return false;
}
int DV(int L, int R) {
while(L < R - 1) {
int mid = L + R >> 1;
if(check(mid)) R = mid;
else L = mid;
}
return R;
}
int main() {
scanf("%d", &n);
for(register int i = 1; i <= n; ++i)
scanf("%d%d", &pt[i].pos[0], &pt[i].pos[1]);
rewM(nmn, nmx);
printf("%d\n", DV(0, 2000000000));
return 0;
}
rockdu
没有帐号? 立即注册