2013 ACM/ICPC Asia Regional Changchun Online

来源:互联网 发布:orb slam2 windows 编辑:程序博客网 时间:2024/04/30 12:06

hdu 4766

先二分答案,然后相当与判断n+1个圆是否有交,注意,只需要判断是否,所以就可以用nlogn的方法来判断。

总体复杂度为nlogn^2,所以跑起来还是很快的

nlogn判断n个圆是否有交是这样的,我们先锁定x的范围,也就是所有圆的右边界的最小值right,以及所有圆的左边界的最大值left

那么n个圆的公共部分肯定在left right之间,而且有一个很重要的性质,如果n个圆的公共部分的左右区间是L,R,假设我们当前枚举的答案是mid,如果x=mid这条直线与所有的圆没有公共部分,那么我们找两个圆与直线的公共部分不相交(其实就是上边界最小以及下边界最大的两个圆),判断这两个圆的公共部分在x=mid的哪一侧即可,其实就是满足二分性质啦~,具体可以看代码

#include <cstdio>#include <cmath>#include <algorithm>using namespace std;const double eps = 1e-8;const double pi = acos(-1.0);struct Point {    double x, y;    Point() {    }    Point(double _x,double _y) {        x = _x ;        y = _y;    }    Point operator - (const Point& t) const {        Point tmp;        tmp.x = x - t.x;        tmp.y = y - t.y;        return tmp;    }    Point operator + (const Point& t) const {        Point tmp;        tmp.x = x + t.x;        tmp.y = y + t.y;        return tmp;    }    bool operator < (const Point &cmp) const {        return x - cmp.x < -eps || (fabs(x-cmp.x)<eps && y -cmp.y < -eps);    }    bool operator == (const Point& t) const {        return fabs(x-t.x) < eps && fabs(y-t.y) < eps;    }}GP;struct Line {    double a,b,c;};double PPdis(Point a,Point b)  {    return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));}double PL_dis(Point p,Line ln) {    return fabs(ln.a*p.x+ln.b*p.y+ln.c) / sqrt(ln.a*ln.a+ln.b*ln.b);}bool Cir_Line(Point ct, double r, Line ln, Point& t1, Point& t2) {   // 直线与圆交点    if ( PL_dis(ct, ln) > r + eps )        return false;    ln.c += ln.a*ct.x + ln.b*ct.y;    if ( fabs(ln.b) < eps ) {        t1.x = t2.x = -ln.c/ln.a;        t1.y = sqrt(r*r - ln.c*ln.c/ln.a/ln.a);        t2.y = -t1.y;    }     else {        double A, B, C;        A = ln.a*ln.a + ln.b*ln.b;        B = 2.0*ln.a*ln.c;        C = ln.c*ln.c - ln.b*ln.b*r*r;        t1.x = (-B - sqrt(B*B - 4.0*A*C))/2.0/A;        t2.x = (-B + sqrt(B*B - 4.0*A*C))/2.0/A;        t1.y = -t1.x*ln.a/ln.b - ln.c/ln.b;        t2.y = -t2.x*ln.a/ln.b - ln.c/ln.b;    }    t1 = t1 + ct;    t2 = t2 + ct;    return true;}bool Cir_Cir(Point c1, double r1, Point c2, double r2, Point& t1, Point& t2) {  // 圆与圆交点    double d = PPdis(c1, c2);    if ( d > r1+r2+eps || d < fabs(r1-r2)-eps )        return false;    Line ln;    ln.a = 2*(c1.x - c2.x);    ln.b = 2*(c1.y - c2.y);    ln.c = r1*r1 - r2*r2 - (c1.x*c1.x+c1.y*c1.y-c2.x*c2.x-c2.y*c2.y);    Cir_Line(c1, r1, ln, t1, t2);    return true;}double R[1010];Point p[1010];int n;bool judge(double mid){    double Left,Right;    for(int i = 0; i <= n; i++) {        if(i == 0) {            Left = p[i].x - R[i];            Right = p[i].x + R[i];        } else{            if(p[i].x-R[i] > Left) Left = p[i].x-R[i];            if(p[i].x+R[i] < Right) Right = p[i].x+R[i];        }    }    if(Left - Right > eps) return false;    int step = 50;    while(step--) {        double mid = (Left + Right)*0.5;        double low,high,uy,dy;        int low_id,high_id;        for(int i = 0; i <= n; i++) {            double d = sqrt(R[i]*R[i]-(p[i].x-mid)*(p[i].x-mid));            uy = p[i].y + d;            dy = p[i].y - d;            if(i == 0) {                low_id = high_id = 0;                low = dy; high = uy;            } else {                if(uy < high) high = uy,high_id = i;                if(dy > low) low = dy,low_id = i;            }        }                if(high - low > -eps) {            return 1;        }        Point a,b;        if(Cir_Cir(p[high_id],R[high_id],p[low_id],R[low_id],a,b)) {            if((a.x+b.x)*0.5 < mid) {                Right = mid;            } else Left = mid;        } else return false;
    }    return false;}int main(){    Point p0;    double d;    while(scanf("%lf%lf",&p0.x,&p0.y)!=EOF) {         scanf("%lf",&d);         scanf("%d",&n);         for(int i = 0; i < n; i++) {             R[i] = d;             scanf("%lf%lf",&p[i].x,&p[i].y);         }         p[n] = p0;         double Left = 0, Right = 1e10, best = -1;         int step = 50;         while(step--) {             double mid = (Left + Right)*0.5;             R[n] = mid;             if(judge(mid)) {                 best = mid;                 Right = mid;             } else Left = mid;         }         if(best == -1) {             puts("X");         }else printf("%.2f\n",best);    }}


原创粉丝点击