给定平面上若干点,用三个等大的正方形去覆盖(在边界上也算被覆盖),边平行于坐标轴,求最小边长。(n leq 20000)
Solution
为什么是三个矩形?
- 对于 (k) 个矩形的覆盖方案,至少各有一个矩形与四条边界重合
而当 (kleq3) 时,如果每个矩形都恰好只沾了一条边界,那么与上述引理矛盾,因此
- 对于 (k leq 3) 个矩形的覆盖方案,至少有一个矩形与边界矩形的一个角重合
因此,考虑二分,检验答案时,我们只需要枚举下一个矩形放在哪个角上,然后算出去掉这些点后的边界,并递归做下去即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 20005;
int n,x[N],y[N],u[N],a;
int dfs(int k) {
int xl=1e9,xr=-1e9,yl=1e9,yr=-1e9;
for(int i=1;i<=n;i++) if(u[i]==0) {
xl=min(xl,x[i]);
yl=min(yl,y[i]);
xr=max(xr,x[i]);
yr=max(yr,y[i]);
}
if(k==1) {
if(xr-xl<=a && yr-yl<=a) return 1;
return 0;
}
else {
int tmp=0;
vector <int> v;
for(int i=1;i<=n;i++) {
if(xl<=x[i] && x[i]<=xl+a && yl<=y[i] && y[i]<=yl+a && u[i]==0) {
v.push_back(i);
u[i]=1;
}
}
tmp = dfs(k-1);
for(int i=0;i<v.size();i++) u[v[i]]=0;
v.clear();
if(tmp) return 1;
for(int i=1;i<=n;i++) {
if(xl<=x[i] && x[i]<=xl+a && yr-a<=y[i] && y[i]<=yr && u[i]==0) {
v.push_back(i);
u[i]=1;
}
}
tmp = dfs(k-1);
for(int i=0;i<v.size();i++) u[v[i]]=0;
v.clear();
if(tmp) return 1;
for(int i=1;i<=n;i++) {
if(xr-a<=x[i] && x[i]<=xr && yl<=y[i] && y[i]<=yl+a && u[i]==0) {
v.push_back(i);
u[i]=1;
}
}
tmp = dfs(k-1);
for(int i=0;i<v.size();i++) u[v[i]]=0;
v.clear();
if(tmp) return 1;
for(int i=1;i<=n;i++) {
if(xr-a<=x[i] && x[i]<=xr && yr-a<=y[i] && y[i]<=yr && u[i]==0) {
v.push_back(i);
u[i]=1;
}
}
tmp = dfs(k-1);
for(int i=0;i<v.size();i++) u[v[i]]=0;
v.clear();
if(tmp) return 1;
}
return 0;
}
int check() {
for(int i=1;i<=n;i++) u[i]=0;
int tmp=dfs(3);
return tmp;
}
signed main() {
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++) cin>>x[i]>>y[i];
int l=0,r=2e9;
while(l<r) {
a=(l+r)/2;
if(check()) r=a;
else l=a+1;
}
cout<<l;
}