[BZOJ3007]拯救小云公主:二分答案+并查集

分析:

看到最短距离最远,很容易想到二分答案。
check()时,将距离小于2*mid的两点间连边,使用并查集判断是否能把矩形的左下角和右上角分开即可。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
const int MAXN=3010;
int n,fa[MAXN];
double Row,Line;
bool vis[MAXN];
struct Boss{
    double x,y;
}a[MAXN];
int Getf(int x){
    return fa[x]==x?x:fa[x]=Getf(fa[x]);
}
inline void Merge(int x,int y){
    int xx=Getf(x),yy=Getf(y);
    if(xx!=yy) fa[yy]=xx;
}
inline bool Check(double mid){
    for(int i=1;i<=n+4;i++) fa[i]=i;
    for(int i=1;i<=n;i++){
        if(a[i].x-1<mid) Merge(i,n+3);
        if(Row-a[i].x<mid) Merge(i,n+1);
        if(a[i].y-1<=mid) Merge(i,n+2);
        if(Line-a[i].y<mid) Merge(i,n+4);
        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)<4*mid*mid) Merge(i,j);
        }
    }
    int Up=Getf(n+1),Left=Getf(n+2),Down=Getf(n+3),Right=Getf(n+4);
    return Up!=Down&&Up!=Right&&Left!=Down&&Left!=Right;
}
int main(){
    n=read(),Row=read(),Line=read();
    for(int i=1;i<=n;i++){
        a[i].x=read(),a[i].y=read();
    }
    double l=0.0,r=min(Row,Line),ans;
    while(r-l>1e-7){
        double mid=(l+r)/2;
        if(Check(mid)) ans=mid,l=mid;
        else r=mid;
    }
    printf("%.2lf\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ErkkiErkko/p/9637233.html
今日推荐