zoukankan      html  css  js  c++  java
  • bzoj2289: 【POJ Challenge】圆,圆,圆

    Description

    1tthinking随便地画了一些圆. ftiasch认为这些圆有交集(面积非零)的可能性不大。因为他实在画了太多圆,所以你被请来判断是否存在交集。

    Input

    第1行,一个整数 N (1 ≤ N ≤ 105), 圆的数量。

    第2到 N 行: 三个整数 Xi, Yi, Ri, 圆心在 (Xi, Yi), 半径为 Ri 的圆。

    Output

    如果存在面积非零的交集,则输出 "YES",否则输出 "NO"。

    首先可以确定如果有相交,x坐标一定在区间[max(x[i]-r[i]),min(x[i]+r[i])]内

    取这个区间中点M,在直线x=M上,若所有圆在这条线上有不为0的交集则可以判断存在面积非0的交集

    否则找出一对圆在x=M上不相交,若两圆相离/相切则可以判断无解,否则把区间缩小到这两个圆交集所在的x坐标区间递归计算

    每次缩小区间至少缩小一半,且圆的坐标和半径是整数,因此复杂度是可以保证的

    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    using namespace std;
    typedef double ld;
    const ld _0=1e-6l;
    const int N=100010;
    int n;
    ld x[N],y[N],r[N];
    ld L,R;
    int read(){
        int x=0,c=getchar(),f=1;
        while(c>57||c<48){if(c=='-')f=-1;c=getchar();}
        while(c>47&&c<58)x=x*10+c-48,c=getchar();
        return x*f;
    }
    void get(int id,ld X,ld&a,ld&b){
        X-=x[id];
        X=sqrt(r[id]*r[id]-X*X);
        a=y[id]-X;
        b=y[id]+X;
    }
    bool chk(ld X,int a,int b){
        if(fabs(X-x[a])>r[a]||fabs(X-x[b])>r[b])return 0;
        ld a1,a2,b1,b2;
        get(a,X,a1,a2);
        get(b,X,b1,b2);
        return a2>b1&&a1<b2;
    }
    void chk(int a,int b){
        ld xd=x[b]-x[a],yd=y[b]-y[a];
        ld d=sqrt(xd*xd+yd*yd);
        if(d+_0>r[a]+r[b]){
            puts("NO");
            exit(0);
        }
        ld s=(r[a]+r[b]+d)/2.;
        ld h=2*sqrt(s*(s-r[a])*(s-r[b])*(s-d))/d;
        ld m=x[a]+xd*sqrt(r[a]*r[a]-h*h)/d,c=h*fabs(yd)/d;
        if(d*d+r[a]*r[a]<r[b]*r[b])m=x[a]*2-m;
        ld lx=m-c,rx=m+c;
        if(lx>x[a]-r[a]&&chk(x[a]-r[a]+_0,a,b))lx=x[a]-r[a];
        if(lx>x[b]-r[b]&&chk(x[b]-r[b]+_0,a,b))lx=x[b]-r[b];
        if(rx<x[a]+r[a]&&chk(x[a]+r[a]-_0,a,b))rx=x[a]+r[a];
        if(rx<x[b]+r[b]&&chk(x[b]+r[b]-_0,a,b))rx=x[b]+r[b];
        if(lx>L)L=lx;
        if(rx<R)R=rx;
    }
    int main(){
        n=read();
        for(int i=0;i<n;i++){
            x[i]=read();
            y[i]=read();
            r[i]=read();
        }
        L=x[0]-r[0],R=x[0]+r[0];
        for(int i=1;i<n;i++){
            if(L<x[i]-r[i])L=x[i]-r[i];
            if(R>x[i]+r[i])R=x[i]+r[i];
        }
        while(1){
            if(L+_0>R){
                puts("NO");
                return 0;
            }
            ld M=(L+R)/2.;
            ld y1,y2,a1,a2;
            get(0,M,y1,y2);
            for(int i=1;i<n;i++){
                get(i,M,a1,a2);
                if(a1>y1)y1=a1;
                if(a2<y2)y2=a2;
                if(y1+_0>y2){
                    for(int j=0;j<i;j++){
                        get(j,M,y1,y2);
                        if(y1>=a2-_0||y2<=a1+_0){
                            chk(i,j);
                            goto re;
                        }
                    }
                }
            }
            puts("YES");
            return 0;
            re:;
        }
    }
  • 相关阅读:
    appium 多线程还是多进程(转)
    清理不可用的模拟器
    ios-元素查看器安装
    Linux 一条命令杀死占用端口的所有进程
    appium 小程序自动化测试
    (转)MitmProxy+APPnium安装使用
    mysql死锁分析
    母线故障跳闸的处理方法(转载)
    电动葫芦使用注意事项(转载)
    三菱plc输出指示灯不亮怎么办(转载)
  • 原文地址:https://www.cnblogs.com/ccz181078/p/5694664.html
Copyright © 2011-2022 走看看