凸包算法实现点集合中搜索凸包顶点的功能,可以处理共线情况,可以输出共线点也可以不输出而只输出凸包顶点。经典的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. JavaMaven【五、Maven集成Eclipse使用】

    创建Maven项目 右键->new->other(Ctrl+n)->Maven Project->quickStart(catalog) 执行指令 右键->Run As- ...

  2. 1.1.EJB概述

    1.EJB概述: Enterprice JavaBeans是一个用于分布式业务应用的标准服务端组件模型.采用Enterprice JavaBeans架构编写的应用是可伸的.事务性的. 多用户安全的.采 ...

  3. ELK展示NGINX访问IP地理位置图

    一.设置NGINX日志格式 [root@zabbix_server ~]# vim /etc/nginx/nginx.conf log_format access_json_log '{"@ ...

  4. C - Covered Points Count CodeForces - 1000C (差分,离散化,统计)

    C - Covered Points Count CodeForces - 1000C You are given nn segments on a coordinate line; each end ...

  5. Access数据库LIKE问题

    access里like的通配符用法是这样:“?”表示任何单一字符: “*”表示零个或多个字符: “#”表示任何一个数字 有时候用%作为通配符不行,需要用*号作为通配符select * from tab ...

  6. Tomcat管理页面

    下面就是 Manager的界面: Server Status 上面个两个配置任意一个配置好了后,都可以启用Server Status的GUI界面:

  7. Java动态绑定与多态

    在面向对象的程序设计语言中,多态是继数据抽象和继承之后的第三种基本特性.多态通过分离做什么和怎么做,从另一个角度将接口和实现分离开来.在一开始接触多态这个词的时候,我们或许会因为这个词本身而感到困惑, ...

  8. union不支持orderByClause、clusterByClause、distributeByClause、sortByClause或limitClause

    union all union 相同点 是 相当于上下拼接 上下两个拼接表必须字段保持一致 不同 union有去重效果,速度会更慢. ================================= ...

  9. 第十一章 前端开发-jQuery

    11.4.0 jQuery 11.4.1 基本知识 定义: jQuery是一个快速,小巧,功能丰富的JavaScript库 作用:它通过易于使用的API在大量浏览器中运行,使得HTML文档遍历和操作, ...

  10. 前端 OSS 自动化部署脚本

    部署脚本 (deploy.js 自己命名) const co = require('co') const OSS = require('ali-oss') const path = require(' ...