返回顶部

【洛谷】P1783 海滩防御 (二分,并查集)

  • 题意:两条垂直边之间有\(n\)个点,问点的半径至少为多少可以将两条边完全封死。

  • 题解:首先对半径进行二分,然后分别统计能到达左边和右边的点,将相交的点用并查集合并起来,然后判断能到达左边的点和右边的点是否在同一个集合即可。

  • 代码

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N= 1e6+10;
    const int mod=1e9+7;
    const int INF= 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
    
    int n,m;
    pair<double,double> pt[N];
    int p[N];
    int L[N],R[N];
    
    double get_dis(double x1,double y1,double x2,double y2){
        return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
    }
    
    int find(int x){
        if(p[x]!=x) p[x]=find(p[x]);
        return p[x];
    }
    
    int main(){
        scanf("%d %d",&n,&m);
    
        for(int i=1;i<=m;++i){
            scanf("%lf %lf",&pt[i].fi,&pt[i].se);
        }
    
        double l=0.0,r=1e9;
        while(r-l>1e-8){
            double mid=(l+r)/2.0;
            for(int i=1;i<=n;++i) p[i]=i,L[i]=0,R[i]=0;
            int cnt1=0,cnt2=0; 
            bool flag=false;
            for(int i=1;i<=n;++i){
                if(pt[i].fi-mid<=0.0) L[++cnt1]=i;
                if(pt[i].fi+mid>=(double)n) R[++cnt2]=i;
                for(int j=i+1;j<=n;++j){
                    double dis=get_dis(pt[i].fi,pt[i].se,pt[j].fi,pt[j].se);
                    if(dis<=2*mid){
                        int fa=find(i);
                        int fb=find(j);
                        p[fa]=fb;
                    }
                }
                for(int i=1;i<=cnt1;++i){
                    for(int j=1;j<=cnt2;++j){
                        int fa=find(L[i]);
                        int fb=find(R[j]);
                        if(fa==fb){
                            flag=true;
                            break;
                        }
                    }
                    if(flag) break;
                }
                if(flag) break;
            }
            if(flag) r=mid;
            else l=mid;
        }
    
        printf("%.2f\n",r);
    
        return 0;
    }
    
    
posted @ 2021-10-10 11:57  Rayotaku  阅读(43)  评论(0编辑  收藏  举报