本文涉及知识点
定义及基础性质
给定一组点,凸包是包括这些点且面积最小的凸多边形。 类比:墙上有若干钉子,弹性无限好的橡皮筋从外面套住这些钉子,橡皮筋最终形成的形状就是凸包。
性质一 :P的端点是pts的子集。

令P上一点p1不在pts中,其相邻的两点为p0,p2。p3在直线p0p1上,p4在直线p1p2上,p1p3和p1p2无穷短。用p3p4p2p0代替p1p2p0面积更小。
性质二 :将pts以x为第一关键字排序,y为第二关键字排序。凸包P必定包括pts[0]。由于没有点的横坐标小于x0=pts[0].X,故P所有端点的横坐标如果小于x0,移到x0,面积更小。P必定有端点横坐标是x0,切纵坐标小于等于pts[0].Y,否则无法包括pts[0]。根据性质一,这样点只能是pts[0]。同理,以y为第一关键字,x为第二关键字排序,P也必定包括pts[0]。
性质三 :以pt0为起点,P逆时针的端点依次为 p t 1 , p t 2 ⋯ p t n − 1 pt_1,p_t2 \cdots pt_{n-1} pt1,pt2⋯ptn−1。以 p t 1 pt_1 pt1为极点,以 p t 2 pt_2 pt2为0度,则 p t 2 ⋅ n pt_{2\cdot n} pt2⋅n的极角 ∈ [ 0 , π ] \in[0,\pi] ∈[0,π]
极角单调性 :凸多边形逆时针顶点为 p 1 , p 2 ⋯ p n p_1,p_2\cdots p_n p1,p2⋯pn。则以pt0起点, p t i pt_i pti极角单调变化。下面用数学归纳法证明:
n=3式,成立。
n>4,假设n-1多变形成立。凸n边型,可以拆分成凸n-1 p 1 P 3 ⋯ p n p_1 P_3 \cdots p_n p1P3⋯pn,三角型 p 1 p 2 p 3 p_1 p_2 p_3 p1p2p3
对于三角型, p 2 的极角 < p 3 极角 p_2的极角 < p_3极角 p2的极角<p3极角;对于n-1边型, p 3 的极角 < p 4 的极角 ⋯ p3的极角 < p4的极角 \cdots p3的极角<p4的极角⋯。
推论一 :以y最小的点为 p 1 p_1 p1, p 2 ⋯ n 在 [ 0 , π ] p_{2\cdots n}在[0,\pi] p2⋯n在[0,π]间单调上升。
Jarvis March(礼品包装算法)
时间复杂度 :O(hn),n是点数,h是P的端点数。由于h是未知的,故确切的时间复杂度是O(nn)。
最大的优点是容易理解。
令P的端点按逆时针顺序为 p 1 , p 2 ⋯ p n p_1,p_2\cdots p_n p1,p2⋯pn,则p1=pts[0]。已知 p 1 ∼ i p_{1 \sim i } p1∼i,求 p i + 1 p_{i+1} pi+1。根据凸多边型的半平面定义,P所有的端点都 p i p i + 1 ⃗ \vec {p_i p_{i+1}} pipi+1 左侧。
next(i)=pts[i]如果在P上,则逆时针下一个端点在pts中的下标。
利用滑动窗口及化环为链求next(i)
以pts[i]为极点,求其它各点极角angs。如果这些极角的跨度超过 π \pi π,则任意经过pts[i]的直线都会将P分成两部分,即pts[i] 一定不是凸包的一点。
angs是环型数组,如果 a n g s [ j ⋯ j − 1 ] < π angs[j\cdots j-1] < \pi angs[j⋯j−1]<π,则anlge[j]对应的点是next(i)。
∀ a n g s \forall angs ∀angs,最多只有一个合法的j。令j1是合法解,则 a n g j 1 到 a n g j > π , j ≠ j 1 ang{j_1}到ang_j>\pi,j\neq j1 angj1到angj>π,j=j1,必定包括此段。
扫描线算法(Graham Scan)
时间复杂度 :O(nlogn)
一,以y为第一关键字x为第二关键字,对pts排序。p0=pts[0]。
二,对pts[ 1 ∼ n − 1 ] 1 \sim n-1] 1∼n−1]按极角排序,p0是极点。
三,pt[ 0 ∼ 2 ] 0\sim 2] 0∼2]入栈。
四,依次处理pts[i],i= 3 ∼ n − 1 3 \sim n-1 3∼n−1
令栈顶元素是b,栈顶元素的前一个元素是a。c=pts[i]。
当 a b ⃗ × b c ⃗ ≤ 0 \vec {ab} \times \vec{bc} \le 0 ab ×bc ≤0时,b出栈。即非左转出栈。
c入栈。
栈中元素就是P的顶点,逆时针。
正确性质证明
证明一 :是凸多边形。
栈中多边型是凸多变形,栈初始是凸多边形,三角型一定凸多边型。增加左转的点后,一定是凸多边形。

由于 p 3 p 4 ⃗ \vec {p3p4} p3p4 左转,故 ∠ p 2 p 3 p 4 < π \angle p2p3p4< \pi ∠p2p3p4<π。
由于p4的极角 ≤ p i \le pi ≤pi,p3的极角 ≥ 0 \ge 0 ≥0, p 4 = π , p 3 = 0 p4=\pi,p3=0 p4=π,p3=0不会同时存在,否则共线。故: ∠ p 3 p 4 p 0 < π \angle p3p4p0 < \pi ∠p3p4p0<π。
p 4 ≠ p i p4 \neq pi p4=pi,否则和p4的x小于p0,与假设矛盾。故 ∠ p 4 p 0 p 1 < π \angle p4p0p1<\pi ∠p4p0p1<π
证明二 :被抛弃的点一定在P内。

p3在凸多变形P1= p 0 p 1 p 2 p 4 p0p1p2p4 p0p1p2p4中,故凸多变形P包括P1,则包括P1中任意一点。 ∠ p 0 p 4 p 2 < π \angle p0p4p2< \pi ∠p0p4p2<π见证明一。根据极角单调性,以p1为极点,p2的极角<p4的极角,故p4 p0都在 p ⃗ 1 p 2 \vec p1p2 p 1p2,故 ∠ p 1 p 2 p 4 < π \angle p1p2p4 < \pi ∠p1p2p4<π
上下凸壳(单调链)
时间复杂度 :O(nlogn),和扫描线相比,不需要调用三角函数。
性质一 :x=x0 和 凸多边P最多只有两个交点。假定有三个交点,依次为p1p2p3,p4和p5是x=x0上距离p2无穷近的点。由于p1p2在P上,故p4在P上;由于p3p4在P上,故p5在P上。即p2两个无穷近的点都在P内,矛盾。
性质二 :如果x=x0和P只有一个交点p0,则P所有的横坐标都小于x0或都大于x0。令p1和p2的横坐标分别大于0,小于0。连接p1p2,和x=x0相交于p3,由于P和x=x0,只有一个交点,故p0=p3。即p3两个无穷近的点都在P内,矛盾。
横坐标最小的点,y小的是plb,y大的时plt;类似横坐标最大的点为prt,prb。plb逆时针到prb经过的端点是下凸壳;prt逆时针到plt是上凸壳。
性质三 :x=x0和上凸壳(下凸壳)顶多只有一个交点。令P最小最大横坐标分别是x1,x2。上凸壳和下凸壳都是x1到x2连续,故x=x0和下凸壳有交点,则和上凸壳也有交点。故x=x0和下凸壳有2个交点,则和上凸壳至少有一个交点,即至少3个交点。与性质一矛盾。
性质四:下凸壳横坐标升序,下凸壳横坐标将序。令下凸壳,逆时针相邻的3个端点为x0,x1,x2。如果x0<x1,x2<x1。则x=x1-无穷小和下凸壳相交了2次,与性质三矛盾。
算法流程
以x为第一关键字,y为第二关键字对pts排序。
第一轮:按顺序对pts[i]按扫描线的方式出栈入栈。
第二轮:逆序对pts[i]按扫描线的方法出栈。
注意 :除掉重复的端点。
性质五 :某凸多边形P,其顶点逆时针为 p 1 p 2 ⋯ p m ⋯ p n p_1 p_2 \cdots p_m \cdots p_n p1p2⋯pm⋯pn。则 p 1 ⋯ p m p_1\cdots p_m p1⋯pm和 p m ⋯ p 1 p_m \cdots p_1 pm⋯p1也是凸多边形。 ∠ p 1 , ∠ p m \angle p_1,\angle p_m ∠p1,∠pm被拆分,其它角不变。之前内角和小于180,之和也小于180。
凸多变形扔掉任意一个三角型后,仍然是凸多边形。变化的两个内角变小。
正确性证明:根据性质五,下凸壳端点按顺序组成多边形是凸多边形,下凸壳也是。分别求然后合并。
性质六 :pts依次三个点为ABC。
情况一:A在下凸壳,BC在上凸壳。以A为极点,根据极角单调性,C到B逆时针。即C在AB右。
情况二:AC在下凸壳,B在上凸壳。

沿着B做x轴的垂线,和AC交于D。BD是垂线和P的两个交点,B在上凸壳,C在下凸壳。故B在D上面。如果B和D重合,则 A B ⃗ B C ⃗ \vec {AB} \vec {BC} AB BC 不旋转。B在D上,顺时针旋转。

扩展阅读
| 我想对大家说的话 |
|---|
| 工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。 |
| 学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作 |
| 有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注 |
| 员工说:技术至上,老板不信;投资人的代表说:技术至上,老板会信。 |
| 闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。 |
| 子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。 |
| 如果程序是一条龙,那算法就是他的是睛 |
| 失败+反思=成功 成功+反思=成功 |
视频课程
先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176
测试环境
操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法 用**C++**实现。
