Hdu 4667 Building Fence

来源:互联网 发布:js给日期控件赋值 编辑:程序博客网 时间:2024/05/22 05:29

Building Fence

这个题有两种解法:

方法一:将圆均分2000个点,暴力水过

程序简单,好写

精度要求比较高,无从下手的时候可以尝试一下,一旦精度要求比较高不过的可能性比较大...

交c++超时,g++800+ms,表示不理解

const int INF = 1000000000;const double eps = 1e-10;const int MOD = 100000007;const int MAXN = 10000000;const double PI = acos(-1.0);///*************基础***********/inline int dcmp(double x){    if(fabs(x) < eps) return 0;    else return x < 0 ? -1 : 1;}struct Point{    double x, y;    Point(double x=0, double y=0):x(x),y(y) { }    inline void read() { scanf("%lf%lf", &x, &y); }};typedef vector<Point> Polygon;typedef Point Vector;inline Vector operator + (Vector A, Vector B) { return Vector(A.x+B.x, A.y+B.y); }inline Vector operator - (Point A, Point B) { return Vector(A.x-B.x, A.y-B.y); }inline Vector operator * (Vector A, double p) { return Vector(A.x*p, A.y*p); }inline Vector operator / (Vector A, double p) { return Vector(A.x/p, A.y/p); }inline bool operator < (const Point& a, const Point& b){    return a.x < b.x || (a.x == b.x && a.y < b.y);}inline bool operator == (const Point& a, const Point &b){    return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;}inline double Dot(Vector A, Vector B){    return A.x*B.x + A.y*B.y;}inline double Length(Vector A){    return sqrt(Dot(A, A));}inline double Angle(Vector A, Vector B){    return acos(Dot(A, B) / Length(A) / Length(B));}inline double angle(Vector v){    return atan2(v.y, v.x);}inline double Cross(Vector A, Vector B){    return A.x*B.y - A.y*B.x;}inline Vector vecunit(Vector x){    return x / Length(x);   //单位向量}inline Vector Normal(Vector x){    return Point(-x.y, x.x) / Length(x);   //垂直法向量}inline Vector Rotate(Vector A, double rad){    return Vector(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad));}// 点集凸包// 如果不希望在凸包的边上有输入点,把两个 <= 改成 <// 注意:输入点集会被修改vector<Point> ConvexHull(vector<Point>& p){    // 预处理,删除重复点    sort(p.begin(), p.end());    p.erase(unique(p.begin(), p.end()), p.end());    int n = p.size();    int m = 0;    vector<Point> ch(n+1);    for(int i = 0; i < n; i++)    {        while(m > 1 && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) <= 0) m--;        ch[m++] = p[i];    }    int k = m;    for(int i = n-2; i >= 0; i--)    {        while(m > k && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) <= 0) m--;        ch[m++] = p[i];    }    if(n > 1) m--;    ch.resize(m);    return ch;}inline double dist(Point a, Point b){    return Length(a - b);}/************圆************/struct Circle{    Point c;    double r;    Circle() {}    Circle(Point c, double r):c(c), r(r) {}    inline Point point(double a) //根据圆心角求点坐标    {        return Point(c.x+cos(a)*r, c.y+sin(a)*r);    }};vector<Point> p, ans;const double interval = PI / 1000;int main(){//    freopen("0.txt", "r", stdin);    int N, M, size;    Point input;    double r, tx, ty, dis, ang;    while (~RII(N, M))    {        ans.clear(), p.clear();        dis = 0;        REP(i, N)        {            scanf("%lf%lf%lf", &tx, &ty, &r);            for (double ang = 0; ang < 2 * PI; ang += interval)            {                input.x = tx + cos(ang) * r;                input.y = ty + sin(ang) * r;                p.push_back(input);            }        }        REP(i, M)        {            input.read();            p.push_back(input);            input.read();            p.push_back(input);            input.read();            p.push_back(input);        }        ans = ConvexHull(p);        size = ans.size();        REP(i, size - 1)        {            dis += Length(ans[i] - ans[i + 1]);        }        dis += dist(ans[size - 1], ans[0]);        printf("%.5lf\n", dis);    }    return 0;}

方法二:

将有可能构成凸包的点计算出来,包括 三角形的顶点,三角形顶点与各个圆的切点,任意两个圆的切点 

然后计算凸包即可

有两个要注意的地方,第一是求凸包边长时候,需要判断一下当前计算的两个点是否在同一个圆上,若是则需要计算圆弧长度

                                     第二是只有一个圆的时候需要特判

const int INF = 0x3f3f3f3f;const double eps = 1e-10;const int MOD = 100000007;const int MAXN = 1000010;const double PI = acos(-1.0);///*************基础***********/double torad(double deg){    return deg / 180 * PI;}inline int dcmp(double x){    if(fabs(x) < eps) return 0;    else return x < 0 ? -1 : 1;}struct Point{    double x, y;    Point(double x=0, double y=0):x(x),y(y) { }    inline void read()    {        scanf("%lf%lf", &x, &y);    }};typedef vector<Point> Polygon;typedef Point Vector;inline Vector operator + (Vector A, Vector B){    return Vector(A.x+B.x, A.y+B.y);}inline Vector operator - (Point A, Point B){    return Vector(A.x-B.x, A.y-B.y);}inline Vector operator * (Vector A, double p){    return Vector(A.x*p, A.y*p);}inline Vector operator / (Vector A, double p){    return Vector(A.x/p, A.y/p);}inline bool operator < (Point a, Point b){    return a.x < b.x || (a.x == b.x && a.y < b.y);}inline bool operator == (Point a, Point b){    return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;}inline double Dot(Vector A, Vector B){    return A.x*B.x + A.y*B.y;}inline double Length(Vector A){    return sqrt(Dot(A, A));}inline double Angle(Vector A, Vector B){    return acos(Dot(A, B) / Length(A) / Length(B));}inline double angle(Vector v){    return atan2(v.y, v.x);}inline double Cross(Vector A, Vector B){    return A.x*B.y - A.y*B.x;}inline Vector Unit(Vector x){    return x / Length(x);   //单位向量}inline Vector Normal(Vector x){    return Point(-x.y, x.x) / Length(x);   //垂直法向量}inline Vector Rotate(Vector A, double rad){    return Vector(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad));}inline double Area2(Point A, Point B, Point C){    return Cross(B-A, C-A);}template <class T> T sqr(T x){    return x * x ;}// 点集凸包// 如果不希望在凸包的边上有输入点,把两个 <= 改成 <// 注意:输入点集会被修改vector<Point> ConvexHull(vector<Point>& p){    // 预处理,删除重复点    sort(p.begin(), p.end());    p.erase(unique(p.begin(), p.end()), p.end());    int n = p.size();    int m = 0;    vector<Point> ch(n+1);    for(int i = 0; i < n; i++)    {        while(m > 1 && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) <= 0) m--;        ch[m++] = p[i];    }    int k = m;    for(int i = n-2; i >= 0; i--)    {        while(m > k && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) <= 0) m--;        ch[m++] = p[i];    }    if(n > 1) m--;    ch.resize(m);    return ch;}inline double dist(Point a, Point b){    return Length(a - b);}/************圆************/struct Circle{    Point c;    double r;    Circle() {}    Circle(Point c, double r):c(c), r(r) {}    inline Point point(double a) //根据圆心角求点坐标    {        return Point(c.x+cos(a)*r, c.y+sin(a)*r);    }    inline void read()    {        scanf("%lf%lf%lf", &c.x, &c.y, &r);    }};//求a点到b点(逆时针)在的圆上的圆弧长度double DisOnCircle(Point a, Point b, Circle C){    double ang1 = angle(a - C.c);    double ang2 = angle(b - C.c);    if (ang2 < ang1) ang2 += 2 * PI;    return C.r * (ang2 - ang1);}// 过点p到圆C的切点int getTangentPoints(Point p, Circle C, vector<Point>& v){    Vector u = C.c - p;    double dist = Length(u);    if(dist < C.r) return 0;    else if(dcmp(dist - C.r) == 0)   // p在圆上,只有一条切线    {        v.push_back(p);        return 1;    }    else    {        double ang = asin(C.r / dist);        double d = sqrt(dist * dist - C.r * C.r);        v.push_back(p + Unit(Rotate(u, -ang)) * d);        v.push_back(p + Unit(Rotate(u, +ang)) * d);        return 2;    }}//圆A与圆B的切点void getTangentPoints(Circle A, Circle B, vector<Point>& a){    if (A.r < B.r) swap(A, B);    ///****************************    int d2 = sqr(A.c.x - B.c.x) + sqr(A.c.y - B.c.y);    int rdiff = A.r - B.r, rsum = A.r + B.r;    if (d2 < rdiff * rdiff) return;   //内含    ///***************************************    double base = atan2(B.c.y - A.c.y, B.c.x - A.c.x);    if (d2 == 0 && A.r == B.r) return;    //无线多条切线    if (d2 == rdiff * rdiff)    //内切, 1条切线    {        ///**********************        a.push_back(A.point(base));        a.push_back(B.point(base));        return;    }    //有外公切线    double ang = acos((A.r - B.r) / sqrt(d2 * 1.0));    a.push_back(A.point(base + ang)); a.push_back(B.point(base + ang));    a.push_back(A.point(base - ang)); a.push_back(B.point(base - ang));    if (d2 == rsum * rsum)  //一条内公切线    {        a.push_back(A.point(base));        a.push_back(B.point(PI + base));    }    else if (d2 > rsum * rsum)  //两条内公切线    {        double ang = acos((A.r + B.r) / sqrt(d2 * 1.0));        a.push_back(A.point(base + ang));        a.push_back(B.point(PI + base + ang));        a.push_back(A.point(base - ang));        a.push_back(B.point(PI + base - ang));    }}inline bool OnCircle(Point x, Circle c){    return dcmp(c.r - Length(c.c - x)) == 0;}Circle C[60];Point P[160];vector<Point> ch, sol;double t1, t2;int main(){    int a, b;    while (~RII(a, b))    {        ch.clear(), sol.clear();        REP(i, a) C[i].read();        b *= 3;        REP(i, b)        {            P[i].read();            sol.push_back(P[i]);        }        REP(i, b) REP(j, a)        {            getTangentPoints(P[i], C[j], sol);        }        FF(i, 0, a) FF(j, i + 1, a)        {            getTangentPoints(C[i], C[j], sol);        }        ch = ConvexHull(sol);        double ans = 0;        int len = ch.size();        REP(i, len)        {            REP(j, a)            {                if (OnCircle(ch[i], C[j]) && OnCircle(ch[(i + 1) % len], C[j]))                {                    ans += DisOnCircle(ch[i], ch[(i + 1) % len], C[j]);                    goto end;                }            }            ans += dist(ch[i], ch[(i + 1) % len]);            end:;        }        if (a == 1 && b == 0)            ans += 2 * PI * C[0].r;        printf("%.5lf\n", ans);    }    return 0;}



原创粉丝点击