【HAOI 2007 覆盖问题】 二分
题解
二分正方形面积,贪心选取最优的情况,算出所有未覆盖的点的最小的矩形。那么正方形每次覆盖一个角的情况是最优,覆盖完一个角后问题又转换成了子问题,最后只要判断是否符合3个正方形即可。
代码
#include <bits/stdc++.h>
using namespace std;
#define FOR0(a,b) for(int i = a; i < b; ++i)
#define FORE(a,b) for(int i = a; i <= b; ++i)
typedef long long ll;
typedef pair<int,int> pii;
int n;
const int maxn = 2e4+5;
struct Point {
ll x, y;
void read() {
ll _x,_y;
scanf("%lld%lld", &_x, &_y);
this->x = _x; this->y = _y;
}
}p[maxn];
bool cov[maxn];
void cover(ll x1,ll y1, ll x2, ll y2) {
for(int i = 0; i < n; ++i) {
if(p[i].x >= x1 && p[i].x <= x2 && p[i].y >= y1 && p[i].y <= y2)
cov[i] = 1;
}
}
void uncover(ll x1,ll y1, ll x2, ll y2) {
for(int i = 0; i < n; ++i) {
if(p[i].x >= x1 && p[i].x <= x2 && p[i].y >= y1 && p[i].y <= y2)
cov[i] = 0;
}
}
void f(ll& x1, ll& y1, ll& x2, ll& y2) {
y1 = x1 = INT_MAX; y2 = x2 = INT_MIN;
// cout << x1 <<" " << x2 << endl;
for(int i = 0; i < n; ++i) {
if(!cov[i]) {
x1 = min(x1,p[i].x);
x2 = max(x2,p[i].x);
y1 = min(y1,p[i].y);
y2 = max(y2,p[i].y);
}
}
}
bool dfs(int cnt, ll k) {
ll x1,y1,x2,y2;
f(x1,y1,x2,y2);
//cout << x1 <<" " << y1 <<" " << x2 << " " << y2 << endl;
if(x2-x1 <= k && y2- y1 <= k)
return true;
if(cnt == 1 )
return false;
bool flag = false;
cover(x1,y1,x1+k,y1+k);
flag |= dfs(cnt-1,k);
uncover(x1,y1,x1+k,y1+k);
cover(x1,y2-k,x1+k,y2);
flag |= dfs(cnt-1,k);
uncover(x1,y2-k,x1+k,y2);
cover(x2-k,y2-k,x2,y2);
flag |= dfs(cnt-1,k);
uncover(x2-k,y2-k,x2,y2);
cover(x2-k,y1,x2,y1+k);
flag |= dfs(cnt-1,k);
uncover(x2-k,y1,x2,y1+k);
return flag;
}
int main() {
scanf("%d", &n);
for(int i = 0; i < n; ++i)
p[i].read();
ll l = 0, r = 1e18, ans = 0;
// cout << dfs(3,0) << endl;
while(l <= r) {
ll mid = (l+r)>>1;
memset(cov, 0,sizeof cov);
if(dfs(3,mid)) {
r = mid-1;
ans = mid;
} else
l = mid+1;
}
cout << ans << endl;
return 0;
}