凸包Graham Scan算法实现
凸包算法实现点集合中搜索凸包顶点的功能,可以处理共线情况,可以输出共线点也可以不输出而只输出凸包顶点。经典的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算法实现的更多相关文章
- 二维凸包 Graham扫描算法
题目链接: http://poj.org/problem?id=1113 求下列点的凸包 求得凸包如下: Graham扫描算法: 找出最左下的点,设为一号点,将其它点对一号点连线,按照与x轴的夹角大小 ...
- Graham Scan凸包算法
获得凸包的算法可以算是计算几何中最基础的算法之一了.寻找凸包的算法有很多种,Graham Scan算法是一种十分简单高效的二维凸包算法,能够在O(nlogn)的时间内找到凸包. 首先介绍一下二维向量的 ...
- 凸包问题 Graham Scan
2020-01-09 15:14:21 凸包问题是计算几何的核心问题,并且凸包问题的研究已经持续了好多年,这中间涌现出了一大批优秀的算法. 凸包问题的最优解法是Graham Scan算法,该算法可以保 ...
- 凸包问题——Graham Scan
Graham Scan 概述: 对于凸多边形的定义不在这里做详细叙述,这里给出算法的实现原理. Step 1: 找出x值最小的点的集合,从其中找出y值最小的点作为初始点 Step 2: 获得新序列后, ...
- POJ 2187 旋转卡壳 + 水平序 Graham 扫描算法 + 运算符重载
水平序 Graham 扫描算法: 计算二维凸包的时候可以用到,Graham 扫描算法有水平序和极角序两种. 极角序算法能一次确定整个凸包, 但是计算极角需要用到三角函数,速度较慢,精度较差,特殊情况较 ...
- 计算几何 二维凸包问题 Andrew算法
凸包:把给定点包围在内部的.面积最小的凸多边形. Andrew算法是Graham算法的变种,速度更快稳定性也更好. 首先把全部点排序.依照第一keywordx第二keywordy从小到大排序,删除反复 ...
- 磁盘寻道时间算法之----------------SCAN算法和最短寻道时间优先调度算法
若干个等待访问磁盘者依次要访问的柱面编号为:80,40,74,14,60,31,61,假设每移动一个柱面需要4毫秒时间,移动到当前位于35号柱面,且当前的移动方向向柱面号增加的方向.请计算: (1)若 ...
- HDU 5928 DP 凸包graham
给出点集,和不大于L长的绳子,问能包裹住的最多点数. 考虑每个点都作为左下角的起点跑一遍极角序求凸包,求的过程中用DP记录当前以j为当前末端为结束的的最小长度,其中一维作为背包的是凸包内侧点的数量.也 ...
- 【计算几何】二维凸包——Graham's Scan法
凸包 点集Q的凸包(convex hull)是指一个最小凸多边形,满足Q中的点或者在多边形边上或者在其内.右图中由红色线段表示的多边形就是点集Q={p0,p1,...p12}的凸包. 一组平面上的点, ...
随机推荐
- mysql_jdbc连接说明
mysql JDBC Driver 常用的有两个,一个是gjt(Giant Java Tree)组织提供的mysql驱动,其JDBC Driver名称(JAVA类名)为:org.gjt.mm.mysq ...
- 7、Nginx基础Http原理
1Http协议概述 HTTP全称HyperText Transfer Protocol中文名为超文本传输协议 1.1.什么是超文本? 包含有超链接(Link)和各种多媒体元素标记的文本.这些超文本文件 ...
- pip命令及虚拟环境的建立
以下命令是pip命令,是帮助我们安装解决python所需要的环境包 列出已经安装的包 pip list 安装要安装的包 pip install 包名 安装特定版本 pip install django ...
- servlet 如何处理多请求访问以及线程讲解
servlet 如何处理多请求访问以及线程讲解 场景:js循环500次请求同一个后台接口,接口内部逻辑:1.查询商品数量,2.扣减商品数量 ,那么该接口是否需要考虑多线程并发安全问题? 分析: 1.先 ...
- 使用CreateWindowEx创建子窗口的注意事项
比如: 使用 HWND child = CreateWindowEx(0,L"childclass",NULL,WS_CHILD | WS_VISIBLE | WS_CLIPSIB ...
- poj1734 Sightseeing trip[最小环]
一个最小环裸题.最小环的两种求法dijkstra和Floyd直接参见这里我就是从这里学的,不想写了. 注意这里最重要的一个点是利用了Floyd的dp过程中路径上点不超过$k$这一性质,来枚举环上最大编 ...
- 运行别人的Vue项目
步骤一:先 安装 cnpm cmd命令下 输入 npm install -g cnpm --registry=http://registry.npm.taobao.org (由于npm有些资源被屏蔽 ...
- ffmpeg 在vs配置的库名称
avcodec.lib; avformat.lib; avutil.lib; avdevice.lib; avfilter.lib;postproc.lib;swresample.lib; swsca ...
- mybatis使用@Insert @SelectKey 执行插入语句时获得主键自增长值(转)
@Insert(" insert into table(c1,c2) " + " values (#{c1},#{c2}) ") @SelectKey(resu ...
- django之ajax结合sweetalert使用,分页器和bulk_create批量插入 07
目录 sweetalert插件 bulk_create 批量插入数据 分页器 简易版本的分页器的推导 自定义分页器的使用(组件) sweetalert插件 有这么一个需求: 当用户进行一个删除数据 ...