凸包算法实现点集合中搜索凸包顶点的功能,可以处理共线情况,可以输出共线点也可以不输出而只输出凸包顶点。经典的Graham Scan算法,点排序使用极角排序方式,并对共线情况做特殊处理。一般算法是将共线的点去掉距离小的,保留最远的,这样处理会导致不能输出凸包边上的点,只能输出顶点。但是有时候需要输出这些边上的点,因此这里我将共线点都保留,并按照顺序排列。共线点排列方式是:非起始边按照从远道近排列,起始边按从近到远排列。

算法原理参见如下网址,讲解很详细:

http://softsurfer.com/Archive/algorithm_0109/algorithm_0109.htm

实现如下:

#include <iostream>

#include <math.h>

using namespace std;

typedef struct{double x,y;} Point;

void qsortpoint(Point s[],Point base,int start,int end);

void sortstartedge(Point s[],int nums);

//向量(x1,y1),(x2,y2)的叉积

double CrossMul(double x1,double y1,double x2,double y2)

{

    return x1*y2-x2*y1;

}

//向量(x1,y1),(x2,y2)的点积

double DotMul(double x1,double y1,double x2,double y2)

{

    return x1*x2+y1*y2;

}

//跨立判断

//判断点c是在向量ab的逆时针方向还是顺时针方向,大于零逆时针,等于0则共线

double CrossMul(Point a,Point b,Point c)

{

    return CrossMul(b.x-a.x,b.y-a.y,c.x-a.x,c.y-a.y);

}

//计算向量ab和ac点积

double DotMul(Point a,Point b,Point c)

{

    return DotMul(b.x-a.x,b.y-a.y,c.x-a.x,c.y-a.y);

}

//判断浮点数符号

int doublecmp(double d)

{

    if(fabs(d)<10e-6)

        return 0;

    return d>0?1:-1;

}

//判断同一直线上的三个点位置,点c是否在点ab之间

bool betweenCmp(Point a,Point b,Point c)

{

    if(doublecmp(DotMul(c,a,b))<=0)

        return true;

    return false;

}

//判断j是否在base->i向量的左边或当共线时j是否位于它们的线段之间

bool isLeftorNearer(Point base,Point i,Point j)

{

    if(CrossMul(base,i,j)>0)

        return true;

    if(CrossMul(base,i,j)==0 && betweenCmp(base,i,j))

        return true;

    return false;

}

void swap(Point& a,Point& b)

{

    Point temp = b;

    b=a;

    a=temp;

}

//以s中的最低点为参考点,对其他所有点进行极角排序(逆时针)

//共线时离参考点较远的点排在前面,凸包的起始边共线点从近到远排列

void sortpoint(Point s[],int nums)

{

    //找最低点

    for(int i=1;i<nums;i++)

    {

        if(s[i].y<s[0].y || (s[i].y==s[0].y && s[i].x<s[0].x))

            swap(s[0],s[i]);

    }

    qsortpoint(s,s[0],1,nums);

    //将起始边上的共线点重新排列

    sortstartedge(s,nums);

}

void sortstartedge(Point s[],int nums)

{

    int i,j;

    for(i=2;i<nums;i++)

    {

        if(CrossMul(s[0],s[1],s[i])!=0)

            break;

    }

    for(j=1;j<(i+1)/2;j++)

        swap(s[j],s[i-j]);

}

//将点按极角逆时针排序

void qsortpoint(Point s[],Point base,int start,int end)

{

    if(start>=end)

        return;

    Point partition = s[end-1];

    int i=start-1,j=start-1;

    while(++j<end-1)

    {

        if(isLeftorNearer(base,s[j],partition))

        {

            swap(s[++i],s[j]);

        }

    }

    swap(s[++i],s[end-1]);

    qsortpoint(s,base,start,i);

    qsortpoint(s,base,i+1,end);

}

void ConvexHull(Point s[],int nums,Point result[],int& resultnums)

{

    sortpoint(s,nums);

resultnums = 0;

    if(nums<=3)

    {

        for(int i=0;i<nums;i++)

            result[resultnums++] = s[i];

        return;

    }

    int top=0;

    int i;

    for(i=0;i<2;i++)

        result[top++] = s[i];

    while(i<nums)

    {

        //用<号判断则包含凸包边上的共线点,<=号判断则只包含凸包顶点

        if(CrossMul(result[top-2],result[top-1],s[i])<=0)

        {

            top--;

        }

        else

        {

            result[top++] = s[i++];

        }

    }

    //最后加入起点形成闭包

    while(CrossMul(result[top-2],result[top-1],s[0])<=0)

    {

        top--;

    }

    result[top++]=s[0];

    resultnums = top;

}

int main()

{

    Point pa[] = {{0,0},{1,0},{2,0},{3,0},{4,0},

                {4,1},{4,2},{4,3},{4,4},

                {3,4},{2,4},{1,4},{0,4},

                {0,3},{0,2},{0,1},{2,2},{1,1}};



    cout<<"convex hull is:"<<endl;

    Point result[18];

    int nums;

    ConvexHull(pa,18,result,nums);

    for(int i=0;i<nums;i++)

        cout<<result[i].x <<"," <<result[i].y<<endl;

    return 0;

}

经验证,算法无误。

凸包Graham Scan算法实现的更多相关文章

  1. 二维凸包 Graham扫描算法

    题目链接: http://poj.org/problem?id=1113 求下列点的凸包 求得凸包如下: Graham扫描算法: 找出最左下的点,设为一号点,将其它点对一号点连线,按照与x轴的夹角大小 ...

  2. Graham Scan凸包算法

    获得凸包的算法可以算是计算几何中最基础的算法之一了.寻找凸包的算法有很多种,Graham Scan算法是一种十分简单高效的二维凸包算法,能够在O(nlogn)的时间内找到凸包. 首先介绍一下二维向量的 ...

  3. 凸包问题 Graham Scan

    2020-01-09 15:14:21 凸包问题是计算几何的核心问题,并且凸包问题的研究已经持续了好多年,这中间涌现出了一大批优秀的算法. 凸包问题的最优解法是Graham Scan算法,该算法可以保 ...

  4. 凸包问题——Graham Scan

    Graham Scan 概述: 对于凸多边形的定义不在这里做详细叙述,这里给出算法的实现原理. Step 1: 找出x值最小的点的集合,从其中找出y值最小的点作为初始点 Step 2: 获得新序列后, ...

  5. POJ 2187 旋转卡壳 + 水平序 Graham 扫描算法 + 运算符重载

    水平序 Graham 扫描算法: 计算二维凸包的时候可以用到,Graham 扫描算法有水平序和极角序两种. 极角序算法能一次确定整个凸包, 但是计算极角需要用到三角函数,速度较慢,精度较差,特殊情况较 ...

  6. 计算几何 二维凸包问题 Andrew算法

    凸包:把给定点包围在内部的.面积最小的凸多边形. Andrew算法是Graham算法的变种,速度更快稳定性也更好. 首先把全部点排序.依照第一keywordx第二keywordy从小到大排序,删除反复 ...

  7. 磁盘寻道时间算法之----------------SCAN算法和最短寻道时间优先调度算法

    若干个等待访问磁盘者依次要访问的柱面编号为:80,40,74,14,60,31,61,假设每移动一个柱面需要4毫秒时间,移动到当前位于35号柱面,且当前的移动方向向柱面号增加的方向.请计算: (1)若 ...

  8. HDU 5928 DP 凸包graham

    给出点集,和不大于L长的绳子,问能包裹住的最多点数. 考虑每个点都作为左下角的起点跑一遍极角序求凸包,求的过程中用DP记录当前以j为当前末端为结束的的最小长度,其中一维作为背包的是凸包内侧点的数量.也 ...

  9. 【计算几何】二维凸包——Graham's Scan法

    凸包 点集Q的凸包(convex hull)是指一个最小凸多边形,满足Q中的点或者在多边形边上或者在其内.右图中由红色线段表示的多边形就是点集Q={p0,p1,...p12}的凸包. 一组平面上的点, ...

随机推荐

  1. mysql_jdbc连接说明

    mysql JDBC Driver 常用的有两个,一个是gjt(Giant Java Tree)组织提供的mysql驱动,其JDBC Driver名称(JAVA类名)为:org.gjt.mm.mysq ...

  2. 7、Nginx基础Http原理

    1Http协议概述 HTTP全称HyperText Transfer Protocol中文名为超文本传输协议 1.1.什么是超文本? 包含有超链接(Link)和各种多媒体元素标记的文本.这些超文本文件 ...

  3. pip命令及虚拟环境的建立

    以下命令是pip命令,是帮助我们安装解决python所需要的环境包 列出已经安装的包 pip list 安装要安装的包 pip install 包名 安装特定版本 pip install django ...

  4. servlet 如何处理多请求访问以及线程讲解

    servlet 如何处理多请求访问以及线程讲解 场景:js循环500次请求同一个后台接口,接口内部逻辑:1.查询商品数量,2.扣减商品数量 ,那么该接口是否需要考虑多线程并发安全问题? 分析: 1.先 ...

  5. 使用CreateWindowEx创建子窗口的注意事项

    比如: 使用 HWND child = CreateWindowEx(0,L"childclass",NULL,WS_CHILD | WS_VISIBLE | WS_CLIPSIB ...

  6. poj1734 Sightseeing trip[最小环]

    一个最小环裸题.最小环的两种求法dijkstra和Floyd直接参见这里我就是从这里学的,不想写了. 注意这里最重要的一个点是利用了Floyd的dp过程中路径上点不超过$k$这一性质,来枚举环上最大编 ...

  7. 运行别人的Vue项目

    步骤一:先 安装 cnpm cmd命令下 输入  npm install -g cnpm --registry=http://registry.npm.taobao.org (由于npm有些资源被屏蔽 ...

  8. ffmpeg 在vs配置的库名称

    avcodec.lib; avformat.lib; avutil.lib; avdevice.lib; avfilter.lib;postproc.lib;swresample.lib; swsca ...

  9. mybatis使用@Insert @SelectKey 执行插入语句时获得主键自增长值(转)

    @Insert(" insert into table(c1,c2) " + " values (#{c1},#{c2}) ") @SelectKey(resu ...

  10. django之ajax结合sweetalert使用,分页器和bulk_create批量插入 07

    目录 sweetalert插件 bulk_create 批量插入数据 分页器 简易版本的分页器的推导 自定义分页器的使用(组件) sweetalert插件 有这么一个需求: ​ 当用户进行一个删除数据 ...