覆盖问题
[HAOI2007] 覆盖问题
题目描述
某人在山上种了 \(N\) 棵小树苗。冬天来了,温度急速下降,小树苗脆弱得不堪一击,于是树主人想用一些塑料薄膜把这些小树遮盖起来,经过一番长久的思考,他决定 用 \(3\) 个 \(L \times L\) 的正方形塑料薄膜将小树遮起来。我们不妨将山建立一个平面直角坐标系,设第 \(i\) 棵小树的坐标为 \((X_i,Y_i)\) ,\(3\) 个 \(L \times L\) 的正方形的边要求平行于坐标轴,一个点如果在正方形的边界上,也算作被覆盖。当然,我们希望塑料薄膜面积越小越好,即求 \(L\) 最小值。
输入格式
接下来有 \(N\) 行,第 \(i+1\) 行有 \(2\) 个整数 \(X_i,Y_i\),表示第 \(i\) 棵树的坐标,保证不会有 \(2\) 个树的坐标相同。
输出格式
一行,输出最小的 \(L\) 值。
样例 #1
样例输入 #1
4
0 1
0 -1
1 0
-1 0
样例输出 #1
1
提示
对于 \(100\%\) 的数据,\(-1,000,000,000 \le X_i,Y_i \le 1,000,000,000。\)
对于 \(30\%\) 的数据,\(N \le 100。\)
对于 \(50\%\) 的数据,\(N \le 2000。\)
对于 \(100\%\) 的数据,\(N \le 20000。\)
看数据范围,我们知道需要开LONGLONG
然后可以通过二分+DFS求解,当然关键就在DFS上,如果纯暴力的话
不用我多说了
这个画图可知,我们从边角开始覆盖是优于从中间开始覆盖的,从中间开始覆盖未知性太多
然后我们可以二分长度L,然后DFS,用flag数组记录\(i\)是在第几次被覆盖的
覆盖时,分4种情况
\(x_{start}=a[i].x\) | \(x_{start}=a[i].x-L\)
\(x_{end}=a[i].x+L\) | \(x_{end}=a[i].x\)
############################
\(y_{start}=a[i].y\) | \(y_{start}=a[i].y-L\)
\(y_{end}=a[i].y+L\) | \(y_{end}=a[i].y\)
然后两两组合
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 20000+10;
int n;
struct ac
{
int x,y;
}a[N];
bool cmp(ac a,ac b)
{
if(a.x==b.x)return a.y>b.y;
return a.x<b.x;
}
int flag[N];
//int stx=INT_MAX,sty=INT_MAX,enx=INT_MIN,eny=INT_MIN,ans;
int ans;
bool dfs(int L,int cnt)
{
int stx=INT_MAX,sty=INT_MAX,enx=INT_MIN,eny=INT_MIN;
for(int i=1;i<=n;i++)
{
if(!flag[i])
{
stx=min(stx,a[i].x);sty=min(sty,a[i].y);
enx=max(enx,a[i].x);eny=max(eny,a[i].y);
}
}
if(max(enx-stx,eny-sty)<=L)return true;
else if(cnt==3)return false;
int cal[4][4];
cal[0][0]=stx,cal[0][1]=stx+L,cal[0][2]=sty,cal[0][3]=sty+L;
cal[1][0]=stx,cal[1][1]=stx+L,cal[1][2]=eny-L,cal[1][3]=eny;
cal[2][0]=enx-L,cal[2][1]=enx,cal[2][2]=sty,cal[2][3]=sty+L;
cal[3][0]=enx-L,cal[3][1]=enx,cal[3][2]=eny-L,cal[3][3]=eny;
for(int j=0;j<4;j++)//j要放在最外面,表示0~3种情况
{
int x1=cal[j][0], x2=cal[j][1], y1=cal[j][2], y2=cal[j][3];
for(int i=1;i<=n;i++)
{
if(!flag[i])
{
if(x1<=a[i].x&&a[i].x<=x2&&y1<=a[i].y&&a[i].y<=y2)
{
flag[i]=cnt;
}
}
}
if(dfs(L,cnt+1))return true;//剪枝
for(int i=1;i<=n;i++)if(flag[i]==cnt)flag[i]=0; //回溯时记得清空
}
return false;
}
bool check(int mid)
{
for(int i=1;i<=n;i++)flag[i]=0;
return dfs(mid,1);
}
void fen(int l,int r)
{
while(l<=r)
{
int mid=(l+r)>>1;
// cout<<mid;
if(check(mid))
{
r=mid-1;
ans=mid;
}else
{
l=mid+1;
}
}
}
main()
{
ios_base::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i].x>>a[i].y;
// stx=min(stx,a[i].x);sty=min(sty,a[i].y);
// enx=max(enx,a[i].x);eny=max(eny,a[i].y);
}
// cout<<stx<<" "<<sty<<" "<<enx<<" "<<eny<<endl;
// sort(a+1,a+1+n,cmp);
fen(0,2e9);
cout<<ans;
return 0;
}