Convex hull algorithm learning

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
This link: https://blog.csdn.net/qq_40733911/article/details/99087622

Reference blog: https://www.cnblogs.com/czaoth/p/6912073.html
https://www.cnblogs.com/aiguona/p/7232243.html
https://baike.baidu.com/item/ convex package

The convex hull concept

Briefly: the given point set on a two-dimensional convex hull is the outermost point of the convex polygon composed of connected, focus point can contain all points.
Here Insert Picture Description
Pictures from Baidu

To achieve the convex hull

The most common convex hull is the convex hull algorithmGraham scan methodwithJarvis Marching
Here onlyGraham scan method
This operation algorithm can be directly on the original data, the spatial complexity is O⑴. But if the result is stored in the convex hull of the other array, may be optimized at code level. Since the convex hull before scanning to be sorted, so the time complexity of at least quicksort O (nlgn). Behind the scanning process complexity is O (n), and therefore the complexity of the algorithm is O (nlgn).


We need to understand a theorem: == Vector vector a × b (× vector cross product), if the result is less than 0, the vector b represents the vector in a clockwise direction; if the result is greater than 0, represents a vector of the vector b counterclockwise; if equal to 0, and the vector b represents a vector parallel.  == (counterclockwise along the two vectors is translated to the origin means connected to the rotational direction from one vector to another is less than 180 degrees).

1. First sort the most lower left corner point, the stack
2 and then sorted according to the polar angle, the second point stack
3. The third point traversing
the cross product is less than 0, abandoned point stack, and then add a new point, or added directly to the new point
4. All points on the convex hull of the resulting stack in which
5 continues writing in accordance with the requirements of the subject

Convex hull templates

I feel it is quite simple to understand

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
const double PI=3.1415926535;
using namespace std;
struct node
{
    int x,y;
};
node vex[1000];//存入的所有的点
node stackk[1000];//凸包中所有的点
int xx,yy;
bool cmp1(node a,node b)//排序找第一个点
{
    if(a.y==b.y)
        return a.x<b.x;
    else
        return a.y<b.y;
}
int cross(node a,node b,node c)//计算叉积
{
    return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}
double dis(node a,node b)//计算距离
{
    return sqrt((a.x-b.x)*(a.x-b.x)*1.0+(a.y-b.y)*(a.y-b.y));
}
bool cmp2(node a,node b)//极角排序另一种方法,速度快
{
    if(atan2(a.y-yy,a.x-xx)!=atan2(b.y-yy,b.x-xx))
        return (atan2(a.y-yy,a.x-xx))<(atan2(b.y-yy,b.x-xx));
    return a.x<b.x;
}
bool cmp(node a,node b)//极角排序
{
    int m=cross(vex[0],a,b);
    if(m>0)
        return 1;
    else if(m==0&&dis(vex[0],a)-dis(vex[0],b)<=0)
        return 1;
    else return 0;
    /*if(m==0)
        return dis(vex[0],a)-dis(vex[0],b)<=0?true:false;
    else
        return m>0?true:false;*/
}
int main()
{

    int t,L;
    while(~scanf("%d",&t))
    {
        int i;
        for(i=0; i<t; i++)
        {
            scanf("%d%d",&vex[i].x,&vex[i].y);
        }
        if(t==1)
            printf("%.2f\n",0.00);
        else if(t==2)
            printf("%.2f\n",dis(vex[0],vex[1]));
        else
        {
            memset(stackk,0,sizeof(stackk));
            sort(vex,vex+t,cmp1);
            stackk[0]=vex[0];
            xx=stackk[0].x;
            yy=stackk[0].y;
            sort(vex+1,vex+t,cmp2);//cmp2是更快的,cmp更容易理解
            stackk[1]=vex[1];//将凸包中的第两个点存入凸包的结构体中
            int top=1;//最后凸包中拥有点的个数
            for(i=2; i<t; i++)
            {
                while(i>=1&&cross(stackk[top-1],stackk[top],vex[i])<0)   //对使用极角排序的i>=1有时可以不用,但加上总是好的
                    top--;
                stackk[++top]=vex[i];                                    //控制<0或<=0可以控制重点,共线的,具体视题目而定。
            }
            double s=0;
            //for(i=1; i<=top; i++)//输出凸包上的点
            //cout<<stackk[i].x<<" "<<stackk[i].y<<endl;
            for(i=1; i<=top; i++)   //计算凸包的周长
                s+=dis(stackk[i-1],stackk[i]);
            s+=dis(stackk[top],vex[0]);//最后一个点和第一个点之间的距离

            printf("%.0f\n",s);
            //得到的s是凸包的周长
        }
    }
}


Getting example convex hull

poj1113
Code:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
const double PI=3.1415926535;
using namespace std;
struct node
{
    int x,y;
};
node vex[1000];//存入的所有的点
node stackk[1000];//凸包中所有的点
int xx,yy;
bool cmp1(node a,node b)//排序找第一个点
{
    if(a.y==b.y)
        return a.x<b.x;
    else
        return a.y<b.y;
}
int cross(node a,node b,node c)//计算叉积
{
    return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}
double dis(node a,node b)//计算距离
{
    return sqrt((a.x-b.x)*(a.x-b.x)*1.0+(a.y-b.y)*(a.y-b.y));
}
bool cmp2(node a,node b)//极角排序另一种方法,速度快
{
    if(atan2(a.y-yy,a.x-xx)!=atan2(b.y-yy,b.x-xx))
        return (atan2(a.y-yy,a.x-xx))<(atan2(b.y-yy,b.x-xx));
    return a.x<b.x;
}
bool cmp(node a,node b)//极角排序
{
    int m=cross(vex[0],a,b);
    if(m>0)
        return 1;
    else if(m==0&&dis(vex[0],a)-dis(vex[0],b)<=0)
        return 1;
    else return 0;
    /*if(m==0)
        return dis(vex[0],a)-dis(vex[0],b)<=0?true:false;
    else
        return m>0?true:false;*/
}
int main()
{

    int t,L;
    double r;
    while(~scanf("%d %lf",&t,&r))
    {
        int i;
        for(i=0; i<t; i++)
        {
            scanf("%d%d",&vex[i].x,&vex[i].y);
        }
        if(t==1)
            printf("%.2f\n",0.00);
        else if(t==2)
            printf("%.2f\n",dis(vex[0],vex[1]));
        else
        {
            memset(stackk,0,sizeof(stackk));
            sort(vex,vex+t,cmp1);
            stackk[0]=vex[0];
            xx=stackk[0].x;
            yy=stackk[0].y;
            sort(vex+1,vex+t,cmp2);//cmp2是更快的,cmp更容易理解
            stackk[1]=vex[1];//将凸包中的第两个点存入凸包的结构体中
            int top=1;//最后凸包中拥有点的个数
            for(i=2; i<t; i++)
            {
                while(i>=1&&cross(stackk[top-1],stackk[top],vex[i])<0)   //对使用极角排序的i>=1有时可以不用,但加上总是好的
                    top--;
                stackk[++top]=vex[i];                                    //控制<0或<=0可以控制重点,共线的,具体视题目而定。
            }
            double s=0;
            //for(i=1; i<=top; i++)//输出凸包上的点
            //cout<<stackk[i].x<<" "<<stackk[i].y<<endl;
            for(i=1; i<=top; i++)   //计算凸包的周长
                s+=dis(stackk[i-1],stackk[i]);
            s+=dis(stackk[top],vex[0]);//最后一个点和第一个点之间的距离
            /*s+=2*PI*L;
            int ans=s+0.5;//四舍五入
            printf("%d\n",ans);*/
            printf("%.0f\n",s+2.0*PI*r);
        }
    }
}


Guess you like

Origin blog.csdn.net/qq_40733911/article/details/99087622
Recommended