凸包算法

来源:互联网 发布:淘宝赵云的盔甲 编辑:程序博客网 时间:2024/04/29 06:02

                凸包

     今天看了一下凸包,自己理解的也不是很深,在这里说说自己的理解 


   凸包:在二维欧几里得空间中,凸包可想象为一条刚好包著所有点的橡皮圈。
      用不严谨的话来讲,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边型,它能          包含点集中所有的点。--百度百科

      
      这几个用蓝线连起来的红点就组成了一个凸包
                         
      
      

     如何求这个凸包呢


                1.首先我们先对这些点进行极角排序
                            
                         极角排序:找y最小的点,如果y最小的点有好几个,那就找x最小的点,相同的点排除掉,把这个点做为                     基点H,接下来所有的点针对该点的射线,按角度由小到大,若相同按距离由近到远来排序
                 
                  如何判断角度的大小,需要左转判定,假如有两个点p1,p2,求出向量<p1,H> (x1,y1)和<p2,H> (x2,y2),
                  如果 x1*y2-x2*y1>0 说明p1到p2左转    
                 
                            排序后应该是这样
     
             

      2.排完序,我们就可以从基点开始找凸包了(Graham算法)
                         1.把排完序的点p0,p1,p2入栈
                         2.判断p[i]与栈内的stack[top],stack[top-1],p[i]到stack[top]是否左转了,如果是,出栈,直到找到
                            p[i]相对于栈内没有左转的时候,把p[i]进栈

                           过程大概是这样的

        第一步  0 , 1 ,2入栈            第二步   1到3左转,2出栈

          
         第三步  1到4右转,4入栈           最后遍历完成,凸包形成
            

         
                          3.遍历完后stack里存的凸包的点,top+1代表点的个数
                          
                           
下面是代码
struct node{    long long x,y;}q[51234],stack1[51234];int n,top;long long dist(node p1,node p2) //两点距离的平方{    return (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y);}long long mult(node p1,node p2,node p0)  //判断是否左转{    return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);}int cmp(node p1,node p2)   //极角排序的比较函数{    if(mult(p1,p2,q[0])>0)        return 1;    else if(mult(p1,p2,q[0])==0 && dist(p1,q[0])<dist(p2,q[0]))  //相等的按距离近的        return 1;    return 0;}void Gramham(){    int i,k=0;    for(i=0;i<n;i++)    {        if(q[i].y<q[k].y || (q[i].y==q[k].y && q[i].x<q[k].x)) //找y最小的点,y相等找x最小的点        k=i;    }    node tep;    tep=q[0];    q[0]=q[k];    q[k]=tep;    sort(q+1,q+n,cmp);    stack1[0]=q[0];    stack1[1]=q[1];    stack1[2]=q[2];    top=2;    for(i=3;i<n;i++)    {        while(top>1 && mult(q[i],stack1[top],stack1[top-1])>=0)  //是否左转,是继续判断,不是,就入栈            top--;        stack1[++top]=q[i];    }}
如有错误,望指出^_^


 
        


1 0