[并查集]JZOJ 5904 刺客信条

Description

          故事发生在1486 年的意大利,Ezio 原本只是一个文艺复兴时期的贵族,后来因为家族成员受到圣殿骑士的杀害,决心成为一名刺客。最终,凭借着他的努力和出众的天赋,成为了杰出的刺客大师。刺客组织在他的带领下,为被剥削的平民声张正义,赶跑了原本统治意大利的圣殿骑士首领-教皇亚历山大六世。在他的一生中,经历了无数次惊心动魄、扣人心弦的探险和刺杀。
        这次的故事就是他暗杀一位作恶多端的红衣主教。红衣主教可以吸取他周围人的生命力量,而他的红衣教徒也拥有这个力量。红衣主教的家是一个x*y 的长方形房间,也就是说,他的家的四个角坐标分别为(0,0)(x,0)(0,y)(x,y)。教堂的门在(0,0) ,而红衣主教就在 (x,y)的卧室休息。他的家中还有n个守护着他的红衣教徒,站在(ai,bi)。Ezio想要趁主教休息时,从门进入潜入到他的卧室刺杀他,因为主教休息时会脱下红衣,这样吸取生命的力量就消失了。可是守卫他的红衣教徒依然很危险,离红衣教徒太近就会被吸取生命。因此,Ezio想知道,在能刺杀主教的前提,从门到他的卧室的路上,他最远和离他最近的红衣教徒保持多远的距离。注意:教徒都在房间里。
 

Input

第一行三个整数x,y,n。之后n行,每行两个整数ai,bi ,意义见题目描述。

Output

一行一个数D,表示Ezio能保持的最大距离,保留两位小数。
 

Sample Input

10 20 2
3 3
6 14

Sample Output

3.00



样例说明
贴着墙走
 

Data Constraint

数据范围
对 10%的数据n<=10,
 对 30%的数据n<=100
对 100%的数据n<=2000
保证输入合法,x,y属于[1,10^6].

分析

连通性问题

如果底边和左边或者左边和右边连通和上边和底边连通或者上边和右边连通,则走不通

那么我们二分一下半径,每次n^2暴力每个点对,用并查集判断是否连通

然后最后,cmath信不得,我把sqrt去掉多拿了10分,把pow去掉又多拿了10分,就AC了

 

//#pragma GCC optimize(2) 
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int N=2e3+10;
struct Point {
    double x,y;
}a[N];
double x,y;
int f[N],rk[N];
int n;

int Get_F(int x) {return x==f[x]?x:f[x]=Get_F(f[x]);}

void Merge(int x,int y) {
    int i=Get_F(x),j=Get_F(y);
    if (rk[i]<rk[j]) {
        rk[j]=max(rk[j],rk[i]+1);
        f[i]=j;
    }
    else {
        rk[i]=max(rk[i],rk[j]+1);
        f[j]=i;
    }
}

int main() {
    freopen("AC.in","r",stdin);
    freopen("AC.out","w",stdout);
    scanf("%lf%lf%d",&x,&y,&n);
    for (int i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y);
    double l=0,r=1e6,mid;
    while (r-l>1e-3) {
        mid=(l+r)/2.0;
        for (int i=1;i<=n+4;i++) f[i]=i,rk[i]=1;
        for (int i=1;i<=n-1;i++)
            for (int j=i+1;j<=n;j++)
                if ((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y)<mid*mid*4.0)
                    Merge(i,j);
        for (int i=1;i<=n;i++) {
            if (a[i].x<mid) Merge(i,n+1);
            if (a[i].y<mid) Merge(i,n+2);
            if (x-a[i].x<mid) Merge(i,n+3);
            if (y-a[i].y<mid) Merge(i,n+4);
        }
        int f1=Get_F(n+1),f2=Get_F(n+2),f3=Get_F(n+3),f4=Get_F(n+4);
        if (f1==f2||f1==f3||f2==f4||f3==f4) r=mid;
            else l=mid+1e-3;
    }
    printf("%.2lf",mid);
}
View Code

 

posted @ 2018-10-15 16:23  Vagari  阅读(278)  评论(0编辑  收藏  举报