HDU 4667 Building Fence

来源:互联网 发布:工程数据类别 编辑:程序博客网 时间:2024/05/22 04:34

 题意: 平面里给出M个三角形, N个圆形, 图形之间两两不相交, 求一个把这些图形围起来周长最小的一个圈的周长~
分析:把三角形顶点分解成点, 对圆形求可能的切点:1.点和圆的两个切点, 2.圆和圆的外公切线切点。  
             然后对所有点求凸包, 处理周长的时候, 如果凸包上两个相邻点在同一个圆上, 则求相应的弧长~。此方法有个trick: 只有一个圆的时候需要特殊处理.
深跪不起:1.对凸包上点取共线点的时候一直wa, 求解释~, 2. 避免直接三角函数, 用精度比较高的方法样例不过~

#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>#include <string>#include <cstring>#include <vector>#define FOR(i, n) for(int i = 0; i < n; i++)#define MEM(array) memset(array, 0, sizeof(array))#define eps 1e-10#define INF (int)1e7#define PI acos(-1.0)#define MAX (int)222using namespace std;inline int sgn(const double &x){return x > eps ? 1 : (x < -eps ? -1 : 0);}inline double sqr(const double &x){return x * x;}struct Point {    double x, y;    Point() {}    Point(const double &xx, const double &yy):x(xx), y(yy) {}    friend Point operator + (const Point &b, const Point &a) {        return Point(b.x + a.x, b.y + a.y);    }    friend Point operator - (const Point &b, const Point &a) {        return Point(b.x - a.x, b.y - a.y);    }    Point operator * (const double &a)const{        return Point(x * a, y * a);    }    Point operator / (const double &a) const{        return Point(x / a, y / a);    }    friend double dot(const Point &a, const Point &b) {        return a.x *b.x + a.y * b.y;    }    friend double det(const Point &a, const Point &b) {        return a.x * b.y - a.y * b.x;    }    double len( )const {        return sqrt(dot(*this, *this));    }    bool operator < (const Point &a)const {        return sgn(x - a.x) < 0 || (sgn(x - a.x) == 0 && sgn(y - a.y) < 0);    }    bool operator == (const Point &a)const {        return sgn(x - a.x ) == 0 && sgn(y - a.y) == 0;    }    Point rotate(double angle){        double x1 = x * cos(angle) - y * sin(angle);        double y1 = x * sin(angle)  + y * cos(angle);        return Point(x1, y1);    }    Point rotate2(const double &cosa,const double &sina){        double x1 = x * cosa - y * sina;        double y1 = x * sina + y * cosa;        return Point(x1, y1);    }    Point norm()const{        return Point(x / len(), y / len());    }    void in(){        scanf("%lf %lf", &x, &y);    }    void out()const {        printf("%.4f    %.4f\n", x, y);    }};int n, m;struct CirPoint{    Point p;    int id;//属于某个圆形    void in(){ p.in(); }    bool operator < (const CirPoint &a)const {        return p < a.p;    }}cp[MAX * MAX], tubao[MAX *  MAX];int ncp, ntb;struct Cir{    Point p;    double r;    friend vector<Point> pointQieCir(const Point &p, const Cir &cir){        Point va = (p - cir.p).norm() * cir.r;        double angle = acos(cir.r / (p - cir.p).len());//        double cosa = cir.r / (p - cir.p).len();//        double sina = sqrt(1 + sqr(cosa));        vector<Point>res;//        res.push_back( cir.p + va.rotate2(cosa, sina));//        res.push_back( cir.p + va.rotate2(cosa, -sina));        res.push_back( cir.p + va.rotate(angle));        res.push_back( cir.p + va.rotate(-angle));        return res;    }    friend void cirWgCir(const Cir &cir1, const int &id1, const Cir &cir2, const int &id2){        Point vn = (cir2.p - cir1.p).norm();        double angle = acos( (cir1.r - cir2.r)/(cir1.p -cir2.p).len() );//        double cosa = cir1.r - cir2.r/(cir1.p -cir2.p).len(), sina = sqrt(1 - sqr(cosa));        Point  vc1 = vn * cir1.r, vc2 = vn * cir2.r;//        Point a = cir1.p + vc1.rotate2(cosa, sina), b = cir1.p + vc1.rotate2(cosa, -sina);        Point a = cir1.p + vc1.rotate(angle), b = cir1.p + vc1.rotate(-angle);        cp[ncp].p = a; cp[ncp++].id = id1;        cp[ncp].p = b; cp[ncp++].id = id1;//        a = cir2.p + vc2.rotate2(cosa, sina); b = cir2.p + vc2.rotate2(cosa, -sina);        a = cir2.p + vc2.rotate(angle); b = cir2.p + vc2.rotate(-angle);        cp[ncp].p = a; cp[ncp++].id = id2;        cp[ncp].p = b; cp[ncp++].id = id2;    }    void in(){        p.in();        scanf("%lf", &r);    }}cir[MAX];void input(){    for(int i = 0; i < n; i++){        cir[i].in();    }    ncp = 0;    for(int i =0; i < m; i++){        for(int j = 0; j < 3; j++){            cp[ncp].in();            cp[ncp++].id = -1;//三角形顶点        }    }}void getCirPoint(){    //point to cir    int tn = ncp;    vector<Point>res;    for(int i = 0; i < tn; i++){        for(int j = 0; j < n; j++){            res = pointQieCir(cp[i].p, cir[j]);            cp[ncp].p = res[0]; cp[ncp++].id = j;            cp[ncp].p = res[1]; cp[ncp++].id = j;        }    }    //cir to cir    for(int i = 0; i < n; i++){        for(int j = i + 1; j < n; j++){            cirWgCir(cir[i], i, cir[j], j);        }    }}void hull(){    ntb = 0;    sort(cp, cp + ncp);    for(int i = 0; i < ncp; i++){        while(ntb > 1 && sgn(det(tubao[ntb - 1].p - tubao[ntb - 2].p,  cp[i].p - tubao[ntb - 2].p)) <= 0)ntb--;        tubao[ntb++] = cp[i];    }    int k = ntb;    for(int i = ncp - 2; i >= 0; i--){        while(ntb > k && sgn(det(tubao[ntb -1].p - tubao[ntb - 2].p, cp[i].p - tubao[ntb - 2].p)) <= 0)ntb--;        tubao[ntb++] = cp[i];    }}void getLen(){    double ans = 0;    for(int i  = 0 ; i < ntb - 1; i++){        if(tubao[i].id != -1 && (tubao[i].id == tubao[(i + 1) ].id)){            Point va = tubao[i].p - cir[tubao[i].id].p;            Point vb = tubao[(i + 1)].p - cir[tubao[i].id].p;            double angle = acos(dot(va, vb)/ va.len() / vb.len());            int res = sgn(det(va, vb));            if(res < 0)angle = 2 * PI - angle;            double t = cir[tubao[i].id].r * angle;            ans += t;        }else {            double t = (tubao[i].p - tubao[(i + 1)].p).len();            ans += t;        }    }    printf("%.10f\n",ans);}int main(){    while(cin>>n>>m){        input();        if(m == 0 && n == 1){//trick            printf("%.10f\n", 2 * PI * cir[0].r);            continue;        }        getCirPoint();        hull();        getLen();    }    return 0;}/**/



原创粉丝点击