平面凸包——学习笔记

什么是平面凸包?
平面凸包(以下简称“凸包”)是指覆盖平面上n个点的最小凸多边形。形象来说就是把n个点看成n根柱子,用橡皮筋去紧框住这n根柱子,最后形成的拉紧的多边形就是要求的凸包。


怎么求平面凸包?

1.Jarvis算法
首先我们需要了解凸包的数学构造法:找一条直线l过其中一点(记为A)并且其他所有点都在l的同侧,则A必为凸包上的一点。那么我们以A为起点,让直线以A为中心绕着同一个方向旋转,碰到的第一个点也在应凸包上(记为B),如果同时碰到多个点,则取距离A最远的那个,然后开始以B为中心继续绕同一个方向旋转,重复此过程直到再次碰到A点,就求出了凸包。而因为计算机无法模拟旋转的过程,每次旋转我们实际上需要对所有点用向量进行检验,时间复杂度为 O ( n ) ,一共要进行凸包上点数次旋转(假设点数为m),所以总时间复杂度为 O ( n m ) ,显然这个时间复杂度不够优秀,在极端情况下甚至会达到 O ( n 2 ) 。所以这种方法仅作为一个铺垫,我们主要掌握后面一种方法。
2.Graham算法
首先我们按Jarvis的思路找到凸包上的一个点(这里取按第一关键字为x,第二关键字为y从小到大排序得到的第一个点),然后对剩下的点进行排序,设置一个候选点的堆栈S,依次扫描每个点,当栈中第二个元素需要逆时针旋转或者不旋转才能从栈顶到达这个点时,栈顶一定不在凸包上(我们取一直旋转的方向为顺时针),弹出栈顶,重复此过程知道不满足条件,最后将这个点入栈即可。这样每个点只会被操作一次,时间复杂度为 O ( n ) ,排序时间复杂度为 O ( n l o g n ) ,所以总时间复杂度为 O ( n l o g n ) ,比Jarvis要优秀不少。


例题:
洛谷P2742 [USACO5.1]圈奶牛Fencing the Cows
这是一道模板题。
代码:

#include <bits/stdc++.h>
using namespace std;

const int maxn=10100;
struct point
{
    double x,y;
    point operator-(point &s)
    {
        return (point){x-s.x,y-s.y};
    }
}p[maxn];
int sta[maxn];
int n,top;

double operator*(point a,point b)
{
    return a.x*b.y-a.y*b.x; 
}

double dist2(point a,point b)
{
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y); 
}

bool judgeonleft(point p0,point p1,point p2)
{
    double s=(p1-p0)*(p2-p0);
    return s<0||(s==0&&dist2(p1,p0)>=dist2(p2,p0)); 
}

bool cmp(point a,point b)
{
    double s=(a-p[1])*(b-p[1]);
    return s<0||(s==0&&dist2(a,p[0])>dist2(b,p[0]));    
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y);
    int first=1;
    for(int i=2;i<=n;i++) if(p[i].x<p[first].x||(p[i].x==p[first].x&&p[i].y<p[first].y)) first=i;
    swap(p[first],p[1]);
    sort(&p[2],&p[n+1],cmp);
    p[n+1]=p[1];
    sta[1]=1;sta[2]=2;
    top=2;
    for(int i=3;i<=n+1;i++)
    {
        while(top>1&&judgeonleft(p[sta[top-1]],p[i],p[sta[top]])) top--;
        sta[++top]=i;   
    }
    top--;
    double ans=0;
    for(int i=1;i<=top;i++)
    {
        if(i==top) ans+=sqrt(dist2(p[sta[top]],p[sta[1]]));
        else ans+=sqrt(dist2(p[sta[i]],p[sta[i+1]]));   
    }
    printf("%.2lf\n",ans);
    return 0;   
}

平面凸包的应用:
平面凸包可以说是求解计算几何问题的准备工作,很多问题都要在凸包上进行操作,而有些计算几何的算法也是建立在凸包的基础上的。具体的内容会在之后的学习笔记和题解中讲解。

猜你喜欢

转载自blog.csdn.net/qq_39662197/article/details/80236645
今日推荐