题目大意:
给出一个 n ∗ m n*m n∗m的图,图上有 T T T个点 ( a i , b i ) (a_i,b_i) (ai,bi),左上角是 ( 0 , 0 ) (0,0) (0,0),右下角是 ( n , m ) (n,m) (n,m),设一条路径从 ( 0 , 0 ) (0,0) (0,0)到 ( n , m ) (n,m) (n,m),其中路径上所有点分别离 T T T个点中最近的点的距离是 x 1 , x 2 x_1,x_2 x1,x2,设其中最小值是 y i y_i yi,问所有从 ( 0 , 0 ) (0,0) (0,0)到 ( n , m ) (n,m) (n,m)的路径中可能出现的 y i y_i yi的最大值是多少。
分析:
二分一个答案
x
x
x,
然后T个
点
点
点分别以
x
x
x为半径,就成了图上有若干个圆,
若干个圆可以构成多个联通块,我们利用并查集求出联通块以后,
判断一下是否存在联通块能把起点到终点的路径给完全挡住即可
代码:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <cmath>
#define eps 1e-6
#define N 2005
using namespace std;
struct Text { bool A, B, C, D; }e[N];
struct Node { double x, y; }a[N];
int fa[N], T;
double n, m ;
int Find(int x)
{
if (fa[x] == x) return x;
fa[x] = Find(fa[x]);
return fa[x];
}
bool Calc(double x)
{
for (int i = 1; i <= T; i++)
e[i].A = e[i].B = e[i].C = e[i].D = 0, fa[i] = i;
for (int i = 1; i <= T; i++)
for (int j = i + 1; j <= T; j++)
{
double chax = a[i].x - a[j].x;
double chay = a[i].y - a[j].y;
if (4 * x * x >= chax * chax + chay * chay)
{
int XX = Find(i), YY = Find(j);
if (XX != YY) fa[XX] = YY;
}
}
for (int i = 1; i <= T; i++)
{
int G = Find(i);
if (a[i].x <= x) e[G].A = 1; //上
if (a[i].x + x >= n) e[G].C = 1; //下
if (a[i].y <= x) e[G].B = 1; //左
if (a[i].y + x >= m) e[G].D = 1; //右
}
for (int i = 1; i <= T; i++)
{
int G = Find(i);
if (e[G].A && e[G].B) return 0; //上左
if (e[G].A && e[G].C) return 0; //上下
if (e[G].B && e[G].D) return 0; //左右
if (e[G].C && e[G].D) return 0; //下右
}
return 1;
}
int main()
{
freopen("AC.in", "r", stdin);
freopen("AC.out", "w", stdout);
scanf("%lf %lf %d", &n, &m, &T);
for (int i = 1; i <= T; i++) scanf("%lf %lf", &a[i].x, &a[i].y);
double ans = 0, l = 0;
double r = (double)sqrt(n * n + m * m);
while (l + eps <= r)
{
double mid = (l + r) / 2;
if (Calc(mid)) ans = mid, l = mid + eps;
else r = mid;
}
printf("%.2lf\n", ans);
return 0;
}