首页 > 代码库 > 计算几何--凸包总结

计算几何--凸包总结

计算几何凸包

       凸包:给你n个散落的点,让你求出最小的凸多边形将所有的点包括起来,或者点在边上。用到的算法是Graham

Graham算法:首先找到一个顶点作为基点,然后将这个点与其他点进行连线,然后按照角度的大小进行排序。

 

然后加点,第一个点肯定在凸多边形上,然后开始加点,每加一个点,要用向量的×积判断以前是不是有边在他的里面,如果有的话,就将这个点替换,这个过程是一个回溯的过程

 

首先找基点,纵坐标最小的一定在凸包上,如果纵坐标相等那么就选横坐标小的。

下面模拟一下Graham算法扫描的过程(截图来自HDU课件)

首相找到基点,很明显p0一定会在凸包上

技术分享        

然后将p0与其他各点相连,按照角度进行排序,排序的时候,不用求出来具体的角度,只需要利用向量的差乘的大小进行排序即可,然后按照角度的顺序进行加点

 技术分享

当加点p3后,发现向量p1p3在向量p2p3的外面,所以p2这个点肯定不在凸包上,所以删掉(这个过程是一个回溯的过程)

 技术分享

然后加点p4没有边在p3p4的外面,继续

 技术分享

加p5的时候,p3p5在p4p5的外面,所以p4这个点也不在凸包上面删掉

 技术分享

重复这个过程每次加点的时候,先要回溯一边,又没有边在要加的这条边的外面

……

最后找到了凸包

 技术分享

那用代码怎么来实现呐?

模板:

/****************************凸包模板*******************************/const double eps = 1e-8;int sgn(double x){    if(fabs(x) < eps)return 0;    if(x < 0)return -1;    else return 1;}struct Point{    double x,y;    Point(){}    Point(double _x,double _y)    {        x = _x;y = _y;    }    Point operator -(const Point &b)const    {        return Point(x - b.x,y - b.y);    }    //叉积    double operator ^(const Point &b)const    {        return x*b.y - y*b.x;    }    //点积    double operator *(const Point &b)const    {        return x*b.x + y*b.y;    }    void input(){        scanf("%lf%lf",&x,&y);    }};struct Line {     Point s,e;     Line(){}     Line(Point _s,Point _e) {                 s = _s; e = _e;     }}; //*两点间距离double dist(Point a,Point b){    return sqrt((a-b)*(a-b));}   /** 求凸包,Graham算法* 点的编号0~n-1* 返回凸包结果Stack[0~top-1]为凸包的编号*/const int MAXN = 1010;Point List[MAXN];int Stack[MAXN];//用来存放凸包的点int top;//表示凸包中点的个数//相对于List[0]的极角排序bool _cmp(Point p1,Point p2){    double tmp = (p1-List[0])^(p2-List[0]);    if(sgn(tmp) > 0)        return true;    else if(sgn(tmp) == 0 && sgn(dist(p1,List[0]) - dist(p2,List[0])) <= 0)        return true;    else         return false;}void Graham(int n){    Point p0;    int k = 0;    p0 = List[0];    //找最下边的一个点    for(int i = 1;i < n;i++)    {        if( (p0.y > List[i].y) || (p0.y == List[i].y && p0.x > List[i].x) )        {            p0 = List[i];            k = i;        }    }    swap(List[k],List[0]);    sort(List+1,List+n,_cmp);    if(n == 1)    {        top = 1;        Stack[0] = 0;        return;    }    if(n == 2)    {        top = 2;        Stack[0] = 0;        Stack[1] = 1;        return ;    }    Stack[0] = 0;    Stack[1] = 1;    top = 2;    for(int i = 2;i < n;i++)    {        while(top > 1 && sgn((List[Stack[top-1]]-List[Stack[top-2]])^(List[i]-List[Stack[top-2]])) <= 0)            top--;        Stack[top++] = i;    }}/****************************凸包模板*******************************/

 

 

计算几何--凸包总结