凸包略解

写篇博客证明窝没有在期末考中AFO

由于笔者太菜,所以只会Andrew算法

其他的算法珂以康这位dalao的博客

Andrew算法

Andrew算法是Graham扫描法的变种,Andrew更快,更稳定

先把所有的点按照x从小到大(x相等时,y也按从小到大)排序

删除重复点(依据题目而确定是否要这个步骤)

画几个图,会发现第一个点和最后一个点都一定在凸包中

我们先从前向后扫描,维护下凸壳

再从后向前扫描,维护上凸壳

这样就能求出凸包,复杂度为\(O(N \log N)\)

完整代码(Luogu P2742 【模板】二维凸包 / [USACO5.1]圈奶牛Fencing the Cows

#include <bits/stdc++.h>
#define db double
#define vec Point
#define N 10005
using namespace std;
struct Point{
    db x,y;
    Point(db x=0,db y=0):x(x),y(y) {}
};
vec operator - (Point a,Point b){
    return vec(a.x-b.x,a.y-b.y);
}
bool operator < (const Point& a,const Point& b){
    return a.x<b.x||(a.x==b.x&&a.y<b.y);
} 
Point p[N],ch[N];
inline db cross(register vec a,register vec b)
{
    return a.x*b.y-a.y*b.x;
}
inline db dis(register Point a,register Point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int main()
{
    int n;
    scanf("%d",&n);
    for(register int i=1;i<=n;++i)
        scanf("%lf%lf",&p[i].x,&p[i].y);
    sort(p+1,p+1+n);
    int m=1;
    for(register int i=1;i<=n;++i)
    {
        while(m>2&&cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)
            --m;
        ch[m++]=p[i];
    }
    int k=m;
    for(register int i=n-1;i;--i)
    {
        while(m>k&&cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)
            --m;
        ch[m++]=p[i];
    }
    db ans=0;
    for(register int i=1;i<m-1;++i)
        ans+=dis(ch[i],ch[i+1]);	
    printf("%.2lf",ans);
    return 0;
}
posted @ 2019-01-21 20:55  JSOI爆零珂学家yzhang  阅读(181)  评论(0编辑  收藏  举报