凸包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}的凸包. 一组平面上的点, ...
随机推荐
- 让框架内循环或者指定元素 指定CSS
p:nth-child(3n+) { background:#ff0000; } http://www.w3school.com.cn/cssref/selector_nth-child.asp
- 1.python环境安装
一:安装Python与环境配置 二:安装pip 三:Anaconda安装和使用 3.1 什么是 Anaconda? Anaconda是专注于数据分析的Python发行版本,支持 Linux, Mac, ...
- Django REST Framework(DRF)_第四篇
DRF分页(总共三种) PageNumberPagination(指定第n页,每页显示n条数据) 说明 既然要用人家的那么我们就先来看下源码,这个分页类源码中举例通过参数指定第几页和每页显示的数据:h ...
- Array 对象-sort()
Array 对象-sort() sort方法对数组成员进行排序,默认是按照字典顺序排序.排序后,原数组将被改变. sort方法不是按照大小排序,而是按照字典顺序.也就是说,数值会被先转成字符串,再按照 ...
- mongodb批量处理
mongodb支持批量插入. 1.使用Java mongodb api 查看源码com.mongodb.MongoCollectionImpl,有两个方法 @Override public void ...
- 【转】分布式文件系统FastDFS原理介绍
什么是FastDFS? FastDFS是一个开源的轻量级分布式文件系统.它解决了大数据量存储和负载均衡等问题.特别适合以中小文件(建议范围:4KB < file_size <500MB)为 ...
- Codeforces Round #451 (Div. 2) [ D. Alarm Clock ] [ E. Squares and not squares ] [ F. Restoring the Expression ]
PROBLEM D. Alarm Clock 题 OvO http://codeforces.com/contest/898/problem/D codeforces 898d 解 从前往后枚举,放进 ...
- 进击JavaScript核心 --- (3)面向对象
JS中的对象定义为:无序属性的结合,其属性可以包含基本值.对象或者函数 1.定义对象的方式 (1).Object构造函数 var student = new Object(); student ...
- 基于node.js的websocket 前后端交互小功能
一.node var ws = require("nodejs-websocket"); console.log("开始建立连接...") var server ...
- MVVM(使用Prism框架)开发WPF
[MVVM]目的是为了分离视图(View)和模型(Model)的耦合——解耦 1.View负责前端展示,与ViewModel进行数据和命令的交互.(双向的数据属性传递,单向的命令属性传递View→Vi ...