二分+暴力判断。
这题的思路很巧啊- -,必须去想最小矩形覆盖后的一些性质。
发现用k(1≤k≤3)个正方形,覆盖平面上所有点,要求边与坐标轴平行,那么如果把所有点用一个最小的矩形(边也与坐标轴平行)圈起来,一定有至少一个正方形的一个顶点和矩形的一个顶点重合。证明就是假设没有这种情况,则肯定有矩形的四条边都和三个正方形的某条边重合,因为正方形只有三个,边有四条,不成立,就算是一些特殊情况想一想也可以知道不成立。
于是二分答案就可以判断了,最小矩形构出来,枚举四个点放正方形,然后继续做下去……
#include<cstdio>
#include<algorithm>
#define N 20005
using namespace std;
const int INF = 0x7ffffff;
struct tree{int x, y;}p[N];
int n, ban[N];
void cover(int x, int y, int len, int op)
{
for(int i = 1; i <= n; i++)
if(p[i].x>=x&&p[i].y>=y&&p[i].x<=x+len&&p[i].y<=y+len)
ban[i]+=op;
}
bool dfs(int t, int a)
{
int l = INF, r = -INF, u = -INF, d = INF;
for(int i = 1; i <= n; i++)
{
if(ban[i]>0)continue;
l=min(l,p[i].x);
r=max(r,p[i].x);
u=max(u,p[i].y);
d=min(d,p[i].y);
}
if(t==3)return (r-l<=a && u-d<=a);
bool flag=0;
if(!flag){cover(l,u-a,a,1);flag=dfs(t+1,a);cover(l,u-a,a,-1);}//左上
if(!flag){cover(l,d,a,1);flag=dfs(t+1,a);cover(l,d,a,-1);}//左下
if(!flag){cover(r-a,u-a,a,1);flag=dfs(t+1,a);cover(r-a,u-a,a,-1);}//右上
if(!flag){cover(r-a,d,a,1);flag=dfs(t+1,a);cover(r-a,d,a,-1);}//右下
return flag;
}
int main()
{
scanf("%d",&n);
for(int i = 1; i <= n; i++)
scanf("%d%d",&p[i].x,&p[i].y);
int l = 0, r = INF;
while(l<r)
{
int mid=(l+r)>>1;
if(dfs(1,mid))r=mid;
else l=mid+1;
}
printf("%d\n",l);
}