和平精英(并查集 + 二分)

**题目描述 **
在未来,和平成为世界主流。但出于战略意义上的考虑,以及训练成果考核的需要,各国约定:每隔一段时间,便进行一场世界范围内的联合军事演习。
2120年的军事演习开始了,演习场地是一个矩形,左上角坐标为(0,0),右下角坐标为 (x,y)。
敌人起始位置在(0,0),我方大本营在 (x,y)。
我方有 n个雷达分布在矩形之中, n个雷达的侦测范围都是半径为 r的圆。
敌人只能在矩形内活动,并且不能走进雷达的侦测范围。
现在,你需要找到一个最小的r,使得敌军不能避开雷达来到我方大本营。

输入描述:
第一行输入n,x,y,表示有n个雷达,矩形的右上角坐标为 (x,y)。其中,1≤n≤100,1≤x,y≤1000000000。
接下来输入 n行,每行包括两个整数ai,bi。代表第i个雷达的坐标(ai,bi)。其中,1≤ai≤x,1≤bi≤y

输出描述:
输出一行,包含一个浮点数ans。(输出保留三位小数)
示例1
输入
1 5 5
2 2

输出
2.000

说明
当唯一一个雷达(2,2)侦察最小半径为2.00时,使得敌军不能避开雷达来到我方大本营。

示例2
输入
2 10 10
1 3
3 1

输出
1.414

说明
当雷达半径约为1.414时,两个雷达侦测范围相切,使得敌军不能避开雷达来到我方大本营。

思路
二分找半径值,对每个点,确认是否与矩形边相交,若相交,则将相交边与点相联系,若该点成的圆与其他点成圆相交,则将两点相联系,最后确认是否能将(0,0)(x,y)切割开来

代码实现

#pragma GCC optimize(3,"Ofast","inline")
#include
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=205;
const int M=20016;
const int INF=0x3f3f3f3f;
const ll LINF=1e18;
const ull sed=31;
const ll mod= 998244353;
const double eps=1e-5;
const double PI=acos(-1.0);
typedef pair<int,int>P;
typedef pair<double,double>Pd;
    
template<class T>void read(T &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch<'0'||ch>'9') {f|=(ch=='-');ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x=f?-x:x;
    return;
}

int n,x,y,fa[N];
Pd p[N];

int Find(int x)
{
    if(fa[x]==x) return x;
    return fa[x]=Find(fa[x]);
}

void merge(int x,int y)
{
    int u=Find(x),v=Find(y);
    if(u==v) return ;
    fa[u]=v;
}

double dist(Pd a,Pd b)
{
    return (a.first-b.first)*(a.first-b.first)+(a.second-b.second)*(a.second-b.second);
}

bool judge(double r)
{
    for(int i=1;i<=n+4;i++) fa[i]=i;
    for(int i=1;i<=n;i++)
    {
        if(p[i].first-r<0) merge(i,n+1);
        if(p[i].first+r>x) merge(i,n+2);
        if(p[i].second+r>y) merge(i,n+3);
        if(p[i].second-r<0) merge(i,n+4);
        for(int j=i+1;j<=n;j++) if(dist(p[i],p[j])<=4*r*r) merge(i,j);
    }
    return Find(n+4)==Find(n+3) || Find(n+1)==Find(n+2) || Find(n+1)==Find(n+4) || Find(n+2)==Find(n+3);
}

int main()
{
    //freopen("a.txt","r",stdin);
    read(n);read(x);read(y);
    for(int i=1;i<=n;i++) scanf("%lf%lf",&p[i].first,&p[i].second);
    double l=0,r=2e9;
    while (r-l>eps)
    {
        double mid=(l+r)/2;
        if(judge(mid)) r=mid;
        else l=mid;
    }
    printf("%.3f\n",l);
    return 0;
}

你可能感兴趣的:(并查集,二分)