Description
Input
Output
Sample Input
10 5 2
1 1
2 3
Sample Output
1.11803399
Data Constraint
Solution
首先二分答案 mid ,那么星星就变成了一个个不能触及的半径为 mid 的圆。
此时两边界也向中间缩了 mid ,如果两边界通过一些圆连在了一起,则说明不可行。
于是我们考虑并查集,把能相连的点(相距小于 mid∗2 )并到一起。
同时每个点也判断一下是否能与边界并到一起。若最后两边界属于同一集合则说明不可行。
但点两两之间判断是否相连是很浪费时间的,时间复杂度达到了 O(K2 logK) 。
对于每个点,我们只需判断与它相邻的四个点即可(左上、左下、右上、右下)。
这些点可以预处理出,时间复杂度就降到了 O(K2) 。
Code
#include<cstdio>
#include<cmath>
using namespace std;
const int N=6003;
const double eps=1e-8;
struct data
{
double x,y;
}a[N];
int n,m,k;
double ans;
int f[N],g[N][4];
inline int read()
{
int X=0,w=1; char ch=0;
while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
return X*w;
}
inline int get(int x)
{
return (f[x]==x)?x:f[x]=get(f[x]);
}
inline double calc(int x,int y)
{
return sqrt((a[x].x-a[y].x)*(a[x].x-a[y].x)+(a[x].y-a[y].y)*(a[x].y-a[y].y));
}
inline bool check(double x)
{
for(int i=1;i<=k+2;i++) f[i]=i;
for(int i=k;i;i--)
for(int j=0;j<4;j++)
if(g[i][j] && calc(i,g[i][j])<=x)
{
int f1=get(i),f2=get(g[i][j]);
if(f1!=f2) f[f1]=f2;
}
for(int i=1;i<=k;i++)
{
if(a[i].y<=x)
{
int f1=get(i),f2=get(k+1);
if(f1!=f2) f[f1]=f2;
}
if(m-a[i].y<=x)
{
int f1=get(i),f2=get(k+2);
if(f1!=f2) f[f1]=f2;
}
}
return get(k+1)!=get(k+2);
}
int main()
{
n=read(),m=read(),k=read();
for(int i=1;i<=k;i++) a[i].x=read(),a[i].y=read();
for(int i=1;i<=k;i++)
for(int j=1;j<=k;j++)
if(i!=j)
{
double x=calc(i,j);
if(a[j].x<=a[i].x && a[j].y<=a[i].y && (!g[i][0] || x<calc(i,g[i][0]))) g[i][0]=j;
if(a[j].x<=a[i].x && a[j].y>a[i].y && (!g[i][1] || x<calc(i,g[i][1]))) g[i][1]=j;
if(a[j].x>a[i].x && a[j].y>a[i].y && (!g[i][2] || x<calc(i,g[i][2]))) g[i][2]=j;
if(a[j].x>a[i].x && a[j].y<=a[i].y && (!g[i][3] || x<calc(i,g[i][3]))) g[i][3]=j;
}
double l=0,r=m;
while(r-l>=eps)
{
double mid=(l+r)/2;
if(check(mid*2)) l=mid+eps,ans=mid; else r=mid-eps;
}
printf("%.8lf",ans);
return 0;
}