题解:
类似于奶酪那道题。可以发现,教徒的控制区域是一个圆形,且要在每个圆的半径相等的情况下,使半径尽可能变大。半径越大,艾吉奥能通过的可能性越低,于是我们可以二分半径。
先预处理出两点之间的距离,尽量不要用sqrt或者pow。然后对于一个给定的半径,我们把相交的两个圆相连,然后,把与边界相交的圆与边界相连。如果我们能够从底边一个圆走到顶边,从左边走到右边,从左边走到下边,从右边走到上边,这几种情况都是不能从左下走到右上的。
我考试的时候是用图来连边,然后DFS判断联通,然后就莫名爆掉。最后是用并查集改对,当然DFS是要比并查集快一些,但并查集比较好些,两者各有优劣。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<climits>
#include<cmath>
#define MAXA 2005
using namespace std;
typedef long long LL;
bool Vis[MAXA];
int Ast[MAXA];
struct Rx {
int a,b;
}Red[MAXA];
LL Dis(LL x1,LL y1,LL x2,LL y2) {
return ((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
int x,y,n,s,e;
double Left,Right,Ans,Mid;
LL Dist[MAXA][MAXA];
int FindAst(int x) {
if(x == Ast[x])
return Ast[x];
Ast[x] = FindAst(Ast[x]);
return Ast[x];
}
bool Check(double R) {
for(int i=0;i<=n+1;i++)
Ast[i] = i;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n && i!=j;j++)
if(Dist[i][j] < 4 * R * R) {
int xAst = FindAst(i);
int yAst = FindAst(j);
Ast[yAst] = xAst;
}
for(int i=1;i<=n;i++) {
int xAst = FindAst(s);
int yAst = FindAst(e);
int zAst = FindAst(i);
if(Red[i].b < R || Red[i].a + R > (double)x)
Ast[xAst] = zAst;
if(Red[i].a < R || Red[i].b + R > (double)y)
Ast[yAst] = zAst;
}
if(FindAst(s) == FindAst(e))
return false;
else return true;
}
int main() {
// freopen("AC.in","r",stdin);
// freopen("AC.out","w",stdout);
scanf("%d %d %d",&x,&y,&n);
for(int i=1;i<=n;i++)
scanf("%d %d",&Red[i].a,&Red[i].b);
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
Dist[i][j] = Dist[j][i] = Dis((LL)Red[i].a,(LL)Red[i].b,(LL)Red[j].a,(LL)Red[j].b);
Right = (double)x * (double)x + (double)y * (double)y;
s = 0;
e = n + 1;
while(Left + 0.001 <= Right) {
Mid = (Left + Right) / 2;
if(Check(Mid)) {
Ans = Mid;
Left = Mid;
}
else Right = Mid;
}
printf("%.2lf",Ans);
}
/*
10 10 4
1 2
7 1
5 5
9 5
*/