bzoj 1052: [HAOI2007]覆盖问题
Description
某人在山上种了N棵小树苗。冬天来了,温度急速下降,小树苗脆弱得不堪一击,于是树主人想用一些塑料薄
膜把这些小树遮盖起来,经过一番长久的思考,他决定用3个LL的正方形塑料薄膜将小树遮起来。我们不妨将山建
立一个平面直角坐标系,设第i棵小树的坐标为(Xi,Yi),3个LL的正方形的边要求平行与坐标轴,一个点如果在
正方形的边界上,也算作被覆盖。当然,我们希望塑料薄膜面积越小越好,即求L最小值。
Input
第一行有一个正整数N,表示有多少棵树。接下来有N行,第i+1行有2个整数Xi,Yi,表示第i棵树的坐标,保证
不会有2个树的坐标相同。
Output
一行,输出最小的L值。
Sample Input
4
0 1
0 -1
1 0
-1 0
Sample Output
1
解题报告:
这题明显的二分答案,至于怎么check,需要想一下,朴素的我们会选择从按x轴左到右扫一遍,然后没有被覆盖的就以该点为正方形的左边,选择能覆盖的点最多的去覆盖,这样处理起来复杂度不对且实现很难,那么考虑贪心,每次找出能覆盖所有的点最小矩形,然后搜索四个角,选择一个去覆盖剩余点,然后不断递归,如果最后层数小于3就符合要求.其实思路和这个差不多,因为矩形一定是卡在点上的,相当于以该点为正方形的某个边,然后尽量多的覆盖点
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
using namespace std;
const int N=30005,inf=2e8;
int x[N],y[N],n;int vis[N];
void updata(int &xl,int &yl,int &xr,int &yr){
xl=yl=inf;xr=yr=-inf;
for(int i=1;i<=n;i++){
if(vis[i])continue;
xl=Min(xl,x[i]);yl=Min(yl,y[i]);
xr=Max(xr,x[i]);yr=Max(yr,y[i]);
}
}
void upd(int xl,int yl,int xr,int yr,int col){
for(int i=1;i<=n;i++){
if(!vis[i] && x[i]>=xl && x[i]<=xr && y[i]>=yl && y[i]<=yr)
vis[i]=col;
}
}
bool dfs(int dep,int mid){
int X[3],Y[3];
updata(X[1],Y[1],X[2],Y[2]);
if(Max(X[2]-X[1],Y[2]-Y[1])<=mid)return true;
if(dep==3)return false;
for(int i=1;i<=2;i++){
for(int j=1;j<=2;j++){
if(i==1){
if(j==1)upd(X[i],Y[j],X[i]+mid,Y[j]+mid,dep);
else upd(X[i],Y[j]-mid,X[i]+mid,Y[j],dep);
}
else{
if(j==1)upd(X[i]-mid,Y[j],X[i],Y[j]+mid,dep);
else upd(X[i]-mid,Y[j]-mid,X[i],Y[j],dep);
}
if(dfs(dep+1,mid))return true;
for(int k=1;k<=n;k++)
if(vis[k]==dep)vis[k]=false;
}
}
return false;
}
bool check(int mid){
memset(vis,0,sizeof(vis));
return dfs(1,mid);
}
void work()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&x[i],&y[i]);
}
int l=1,r=2e9,mid,ans=-1;
while(l<=r){
mid=(l+r)>>1;
if(check(mid))ans=mid,r=mid-1;
else l=mid+1;
}
printf("%d\n",ans);
}
int main()
{
work();
return 0;
}