1. 程式人生 > >求凸包的周長(計算幾何模板)

求凸包的周長(計算幾何模板)

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 110;
const double eps = 1e-8;
const double PI = 3.1415926535898;
struct point
{
    double x,y;
}s[N],t[N];
bool isZero(double x)
{
    return (x>0?x:-x)<eps;
}
double dis(point a,point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
//叉積
double crossProd(point a,point b,point c)
{
    return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
//以最左下的點為基準點,其他各點(逆時針方向)以極角從小到大的排序規則
int cmp(const void * a,const void * b)
{
    point *c = (point *)a;
    point *d = (point *)b;
    double k = crossProd(t[0],*c,*d);
    if(k<eps||(isZero(k) && (dis(t[0],*c)>dis(t[0],*d))))
        return 1;
    return -1;
}
double Graham(int n) {
    double x = t[0].x;
    double y = t[0].y;
    int k = 0;
    for (int i=1; i<n; ++i)
    {//找到最左下的一個點
        if (t[i].x<x || (t[i].x==x && t[i].y<y)) {
            x = t[i].x;
            y = t[i].y;
            k = i;
        }
    }
    //交換,將最左的點移至陣列首位
    point tmp = t[k];
    t[k] = t[0];
    t[0] = tmp;
    qsort(t+1, n-1, sizeof(point), cmp);
//    sort(t+1,n-1,cmp);
    t[n] = t[0];
    s[0] = t[0];
    s[1] = t[1];
    s[2] = t[2];
    int top = 2;
    for (int i=3; i<=n; ++i)
    {//加入一個點後,向右偏拐或共線,則上一個點不在凸包內,則--top,該過程直到不向右偏拐或沒有三點共線的點
        while (crossProd(s[top-1], s[top], t[i])<=eps && top>=2) --top;
        s[++top] = t[i];//在當前情況下符合凸包的點,入棧
    }
    double len = 0;
    for (int i=0; i<top; ++i) len += dis(s[i], s[i+1]);
    return len;
}
int main()
{
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    int n;
    double r;
    scanf("%d%lf",&n,&r);
    for(int i=0;i<n;i++)
    {
        scanf("%lf%lf",&t[i].x,&t[i].y);
    }
    if(n==1)
    {
        printf("%.2lf\n",2*PI*r);
    }
    else if(n==2)
    {
        printf("%.2lf\n",2*(PI*r+dis(t[0],t[1])));
    }
    else
    {
        printf("%.2lf\n",Graham(n)+2*PI*r);
    }
    return 0;
}