图解 Andrew 算法求凸包
前言
Andrew 算法可以在 \(O(n\log n)\) 的时间复杂度通过单调栈分别求出散点的上凸壳和下凸壳,来求出平面上一些点的凸包。
看懂这篇博客,大家需要掌握:
- 基础计算几何知识
- 单调栈
凸包
首先,什么是凸包?
给你平面上的点集,你需要从中选出最少的点,使得这些点所组成的 凸多边形 可以包裹住其他所有点。这些点所组成的凸多边形就是凸包。
譬如下面这个点集:

它的凸包是:

下面我将会告诉大家怎么求。
序曲
Andrew 算法需要先对所有点按照 \(x\) 坐标为第一关键字、\(y\) 坐标为第二关键字排序。如上面的点集,经过排序后是:
ABFEDCGJHILMNKO
那么 \(A\) 和 \(O\) 一定在凸包上,因为它们无法被其他点所组成的凸多边形覆盖。
按照 Andrew 算法的逻辑,我们需要先求出凸包的一半 “凸壳”。下面将会以上凸壳为例,下凸壳与其类似。
一段上凸壳一定满足顺时针遍历时,每个节点在每条边所组成的向量的右边(下凸壳在左边)(就是凸包的“凸”,下同)。这句话大家可能不能完全理解,不过没有关系,我会给大家慢慢道来。
流程
首先,按照排序后的点集遍历点集,第一个遍历到的是 \(B\)(\(A\) 不考虑)。我们可以连接 \(AB\):

然后下一个点是 \(F\),继续连接 \(BF\):

下一个点是 \(E\),继续连接 \(FE\):

下一个点是 \(D\),继续连接 \(ED\):

但是这样子我们遇到了问题,\(D\) 在 \(FE\) 左侧,它不凸了,我们的解决办法是:
断掉以前连的边,直到遇到可以连接的点,满足凸壳性质
我们可以断掉 \(ED,FE\),连接 \(FD\),发现还是不满足。

我们继续,断掉 \(FD,BF\),连接 \(BD\),这回满足了。

下一个点是 \(C\),继续连接 \(DC\):

发现又不凸了,我们断掉 \(DC,BD\) 连接 \(BC\),就可以满足了:

下一个点是 \(G\),继续连接 \(CG\):

发现不凸,我们断掉 \(CG,BC\),连接 \(BG\):

下一个点是 \(J\),继续连接 \(GJ\):

下一个点是 \(H\),继续连接 \(JH\):

发现不凸,我们断掉 \(GJ,JH\),连接 \(GH\):

下一个点是 \(I\),继续连接 \(HI\):

下一个点是 \(L\),继续连接 \(IL\):

发现不凸,我们断掉 \(IL,HI\),连接 \(HL\):

发现不凸,我们断掉 \(HL,GH\),连接 \(GL\):

发现不凸,我们断掉 \(GL,BG\),连接 \(BL\):

下一个点是 \(M\),继续连接 \(LM\):

下一个点是 \(N\),继续连接 \(MN\):

发现不凸,我们断掉 \(MN,LM\),连接 \(LN\):

下一个点是 \(K\),继续连接 \(NK\):

发现不凸,我们断掉 \(LN,NK\),连接 \(LK\):

最后一个点是 \(O\),我们连接 \(KO\):

这样子上凸壳便求出来,下凸壳我们一般从 \(O\) 遍历到 \(A\),按照以前的逻辑做即可,最后结果如下:

实现
维护“不凸就断边”我们使用单调栈,如果不满足凸的性质就弹栈,最后入栈即可。注意我们不需要模拟断边操作,只需要将点删除即可。
还有,如何判断是否在左边呢?我们可以使用叉乘的右手定则:

参考代码如下:
int stk[100005];
bool used[100005];
vector<Point> ConvexHull(Point* poly, int n){ // Andrew算法求凸包
int top=0;
sort(poly+1,poly+n+1,[&](Point x,Point y){
return (x.x==y.x)?(x.y<y.y):(x.x<y.x);
});
stk[++top]=1;
for(int i=2;i<=n;i++){
while(top>1&&dcmp((poly[stk[top]]-poly[stk[top-1]])*(poly[i]-poly[stk[top]]))<=0){
used[stk[top--]]=0;
}
used[i]=1;
stk[++top]=i;
}
int tmp=top;
for(int i=n-1;i;i--){
if(used[i]) continue;
while(top>tmp&&dcmp((poly[stk[top]]-poly[stk[top-1]])*(poly[i]-poly[stk[top]]))<=0){
used[stk[top--]]=0;
}
used[i]=1;
stk[++top]=i;
}
vector<Point> a;
for(int i=1;i<=top;i++){
a.push_back(poly[stk[i]]);
}
return a;
}
课后习题
图解 Andrew 算法求凸包的更多相关文章
- (模板)graham扫描法、andrew算法求凸包
凸包算法讲解:Click Here 题目链接:https://vjudge.net/problem/POJ-1113 题意:简化下题意即求凸包的周长+2×PI×r. 思路:用graham求凸包,模板是 ...
- Andrew算法求二维凸包-学习笔记
凸包的概念 首先,引入凸包的概念: (有点窄的时候...图片右边可能会被吞,拉开图片看就可以了) 大概长这个样子: 那么,给定一些散点,如何快速地求出凸包呢(用在凸包上的点来表示凸包) Andrew算 ...
- LA 4728 旋转卡壳算法求凸包的最大直径
#include<iostream> #include<cstdio> #include<cmath> #include<vector> #includ ...
- nyoj-78-圈水池(Graham算法求凸包)
题目链接 /* Name:nyoj-78-圈水池 Copyright: Author: Date: 2018/4/27 9:52:48 Description: Graham求凸包 zyj大佬的模板, ...
- [poj1113][Wall] (水平序+graham算法 求凸包)
Description Once upon a time there was a greedy King who ordered his chief Architect to build a wall ...
- POJ 2187 Beauty Contest【旋转卡壳求凸包直径】
链接: http://poj.org/problem?id=2187 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=22013#probl ...
- 计算几何 二维凸包问题 Andrew算法
凸包:把给定点包围在内部的.面积最小的凸多边形. Andrew算法是Graham算法的变种,速度更快稳定性也更好. 首先把全部点排序.依照第一keywordx第二keywordy从小到大排序,删除反复 ...
- Beauty Contest(graham求凸包算法)
Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 25256 Accepted: 7756 Description Bess ...
- 算法模板——计算几何2(二维凸包——Andrew算法)
实现功能:求出二维平面内一对散点的凸包(详见Codevs 1298) 很神奇的算法——先将各个点按坐标排序,然后像我们所知的那样一路左转,求出半边的凸包,然后反过来求另一半的凸包 我以前正是因为总抱着 ...
- Codeforces Round #113 (Div. 2) B. Polygons Andrew求凸包
B. Polygons time limit per test 2 seconds memory limit per test 256 megabytes input standard input o ...
随机推荐
- 成功解决Initialization failed for ‘https://start.spring.io‘ Please check URL, network and proxy settings
文章目录 1.问题描述 2.问题的解决方式 2.1 查看网络连接问题 2.2 设置代理 2.3 直接连接阿里云下载模板 1.问题描述 建立springboot项目的时候发现不能初始化成功,我真的栓Q ...
- 齐博x1 万能fun 调用任意数据表 任意字段就是这么任性调用
列举了几个常用的查询进行简单封装,虽然系统也有内置的但是很多人不大会就二次封装简化了一下. 这里只封装了一个条件 多个条件的自己再封装或者用标签解决比较好 这里只是说fun可以万能调用 1获取任意表的 ...
- 深入浅出redis缓存应用
0.1.索引 https://blog.waterflow.link/articles/1663169309611 1.只读缓存 只读缓存的流程是这样的: 当查询请求过来时,先从redis中查询数据, ...
- C语言/python实现定时关机
1.python def shutdown(): print('(1)定时关机\n(2)取消定时关机\n(3)立即关机\n(4)关机重启') b = eval(input('请选择:\n')) if( ...
- 题解 P4058 [Code+#1]木材
前言 这什么题啊,不就是个二分答案我从65到100都经历了一遍--(瞬间气哭) \(\sf {Solution}\) 题目理解起来不难的,大意就懒得写了. 一眼二分答案. 此题属于在形如 \(\{0, ...
- JS 学习笔记 (七) 面向对象编程OOP
1.前言 创建对象有很多种方法,最常见的是字面量创建和new Object()创建.但是在需要创建多个相同结构的对象时,这两种方法就不太方便了. 如:创建多个学生信息的对象 let tom = { n ...
- OpenHarmony移植案例: build lite源码分析之hb命令__entry__.py
摘要:本文介绍了build lite 轻量级编译构建系统hb命令的源码,主要分析了_\entry__.py文件. 本文分享自华为云社区<移植案例与原理 - build lite源码分析 之 hb ...
- 图扑软件 3D 组态编辑器,低代码零代码构建数字孪生工厂
行业背景 随着中国制造 2025 计划的提出,新一轮的工业改革拉开序幕.大数据积累的指数级增长为智能商业爆发奠定了良好的基础,传统制造业高污染.高能耗.低效率的生产模式已不符合现代工业要求. 图扑拖拽 ...
- hutool包的DateUtil工具类
[首先引入依赖 ] <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-core& ...
- Atlas人工智能基础知识
目录 一. AI基本概念 1.人工智能是什么 2.人工智能.机器学习.深度学习的关系是什么 2.监督学习.无监督学习.半监督学习和强化学习是什么 3.什么是模型和网络 4.什么是训练和推理 5.什么 ...