Template - Computational Geometry (Collection)

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;


int solve();

int main() {
#ifdef Yinku
    freopen("Yinku.in","r",stdin);
#endif // Yinku
    solve();
}

//不要输出-0.0之类的数

const double eps=1e-8;
const double pi=acos(-1.0);

//判断浮点数的符号
inline int cmp(double x) {
    return (fabs(x)<eps)?0:((x>0.0)?1:-1);
}

inline double sqr(double x) {
    return x*x;
}

struct Point {
    double x,y;
    Point() {};
    Point(const double x,const double y):x(x),y(y) {};

    friend Point operator+(const Point &a,const Point &b) {
        return Point(a.x+b.x,a.y+b.y);
    }
    friend Point operator-(const Point &a,const Point &b) {
        return Point(a.x-b.x,a.y-b.y);
    }
    friend Point operator*(const Point &p,const double k) {
        return Point(p.x*k,p.y*k);
    }
    friend Point operator*(const double k,const Point &p) {
        return Point(p.x*k,p.y*k);
    }
    friend Point operator/(const Point &p,const double k) {
        return Point(p.x/k,p.y/k);
    }
    friend bool operator==(const Point &a,const Point &b) {
        return cmp(a.x-b.x)==0&&cmp(a.y-b.y)==0;
    }
    Point rotate(double A) {
        //向量绕原点旋转A弧度
        return Point(x*cos(A)-y*sin(A),x*sin(A)+y*cos(A));
    }
    double norm() {
        return sqrt(sqr(x)+sqr(y));
    }
};

double det(const Point &a,const Point &b) {
    return a.x*b.y-a.y*b.x;
}
double dot(const Point &a,const Point &b) {
    return a.x*b.x+a.y*b.y;
}
double dist(const Point &a,const Point &b) {
    return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
}


struct Line {
    Point a,b;
    Line() {};
    Line(const Point &a,const Point &b):a(a),b(b) {};
    Line move_dist(const double &d) {
        //向法向平移d单位长度
        //单位法向量n,从a指向b
        Point n=b-a;
        n=n/n.norm();
        //左旋90度
        n=n.rotate(pi/2.0);
        return Line(a+n*d,b+n*d);
    }
};

double dist_point_to_line(const Point &p,const Line &l) {
    Point a=l.a,b=l.b;
    //当a与b可以重合时,这里要加上下面的语句
    /*if(a==b)
        return a.dist(p);*/
    if(cmp(dot(p-a,b-a))<0)
        return dist(p,a);
    if(cmp(dot(p-b,a-b))<0)
        return dist(p,b);
    return fabs(det(a-p,b-p)/dist(a,b));
}
Point point_project_on_line(const Point &p,const Line &l)  {
    Point a=l.a,b=l.b;
    double r=dot(b-a,p-a)/dot(b-a,b-a);
    return a+(b-a)*r;
}
bool point_on_line(const Point &p,const Line &l)  {
    Point a=l.a,b=l.b;
    //这里的line是线段
    //第一个cmp意思是叉积等于0,意味着直线穿过该点
    //第二个cmp的<=意思是点在线段内(含端点),当改为<为点在线段内(不含端点)
    return cmp(det(p-a,b-a))==0&&cmp(dot(p-a,p-b))<=0;
}
bool parallel(const Line &tl,const Line &l)  {
    Point a=tl.a,b=tl.b;
    //叉积等于0,意味着向量平行
    return !cmp(det(a-b,l.a-l.b));
}
bool intersect(const Line &tl,const Line &l,Point &p) {
    Point a=tl.a,b=tl.b;
    //判断直线是否相交,相交则求出交点(不需要交点可以直接return)
    if(parallel(tl,l))
        return false;
    double s1=det(a-l.a,l.b-l.a);
    double s2=det(b-l.a,l.b-l.a);
    p=(b*s1-a*s2)/(s1-s2);
    return true;
}


const int MAXN=10005;
struct Polygon {
    int n;
    Point a[MAXN];
    Polygon() {};
    double perimeter() {
        double sum=0.0;
        a[n]=a[0];
        for(int i=0; i<n; i++)
            sum+=(a[i+1]-a[i]).norm();
        return sum;
    }
    double area() {
        double sum=0.0;
        a[n]=a[0];
        for(int i=0; i<n; i++)
            sum+=det(a[i+1],a[i]);
        return sum/2.0;
    }
    Point masscenter() {
        Point ans(0.0,0.0);
        //在这里,当多边形面积为0,返回的是原点
        if(cmp(area())==0)
            return ans;
        a[n]=a[0];
        for(int i=0; i<n; i++)
            ans=ans+(a[i]+a[i+1])*det(a[i+1],a[i]);
        return ans/area()/6.0;
    }
    //下面两个只有格点多边形能用
    int border_point_num() {
        int num=0;
        a[n]=a[0];
        for(int i=0; i<n; i++)
            num+=__gcd(abs(int(a[i+1].x-a[i].x)),abs(int(a[i+1].y-a[i].y)));
        return num;
    }
    int inside_point_num() {
        return (int)area()+1-border_point_num()/2;
    }
};

int point_in_polygon(Point &p,Polygon &po) {
    Point *a=po.a;
    int n=po.n;
    int num=0,d1,d2,k;

    a[n]=a[0];
    for(int i=0; i<n; i++) {
        if(point_on_line(p,Line(a[i],a[i+1])))
            return 2;
        k=cmp(det(a[i+1]-a[i],p-a[i]));
        d1=cmp(a[i].y-p.y);
        d2=cmp(a[i+1].y-p.y);
        if(k>0&&d1<=0&&d2>0)
            num++;
        if(k<0&&d2<=0&&d1>0)
            num--;
    }
    return num!=0;
}

struct Polygon_Convex {
    vector<Point> P;
    Polygon_Convex(int Size=0) {
        P.resize(Size);
    }
    Polygon to_polygon() {
        //注意多边形的最大点数要够
        Polygon p;
        p.n=P.size();
        for(int i=0; i<p.n; i++) {
            p.a[i]=P[i];
        }
        return p;
    }
};

bool comp_less(const Point&a,const Point &b) {
    //水平序
    return cmp(a.x-b.x)<0||cmp(a.x-b.x)==0&&cmp(a.y-b.y)<0;
}
Polygon_Convex convex_hull(vector<Point> a) {
    Polygon_Convex res(2*a.size()+5);
    sort(a.begin(),a.end(),comp_less);
    a.erase(unique(a.begin(),a.end()),a.end());
    int m=0;
    for(int i=0; i<a.size(); ++i) {
        while(m>1&&cmp(det(res.P[m-1]-res.P[m-2],a[i]-res.P[m-2]))<=0)
            --m;
        res.P[m++]=a[i];
    }

    int k=m;
    for(int i=int(a.size())-2; i>=0; --i) {
        while(m>k&&cmp(det(res.P[m-1]-res.P[m-2],a[i]-res.P[m-2])<=0))
            --m;
        res.P[m++]=a[i];
    }
    //当只有一个点时,凸包保留一个点,否则结尾和开头重复了
    res.P.resize(m-(a.size()>1));
    return res;
}

int solve() {
    int n;
    scanf("%d",&n);
    vector<Point> a(n);
    for(int i=0; i<n; i++) {
        scanf("%lf%lf",&a[i].x,&a[i].y);
    }
    printf("%.2f\n",convex_hull(a).to_polygon().perimeter());
    return 0;
}

Guess you like

Origin www.cnblogs.com/Yinku/p/10954747.html