[toc]

https://oi-wiki.org/geometry/convex-hull/# 凸多边形

# 凸包

在给定平面上能够包含给定点的最小的凸多边形叫做凸包

使用三角不等式可以证明最小凸多边形的周长最小

# Andrew 算法求凸包

# 二维凸包

    1. 把所有点以横坐标为第一关键字,纵坐标为第二关键字排序,排序后最小元素和最大元素一定在凸包上
    1. 从一个点出发逆时针走,出现右拐,则不在凸包上,使用单调栈来维护上下凸壳

伪代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// C++ Version
// stk[] 是整型,存的是下标
// p[] 存储向量或点
tp = 0; // 初始化栈
std::sort(p + 1, p + 1 + n); // 对点进行排序
stk[++tp] = 1;
// 栈内添加第一个元素,且不更新 used,使得 1 在最后封闭凸包时也对单调栈更新
for (int i = 2; i <= n; ++i) {
while (tp >= 2 // 下一行 * 操作符被重载为叉积
&& (p[stk[tp]] - p[stk[tp - 1]]) * (p[i] - p[stk[tp]]) <= 0)
used[stk[tp--]] = 0;
used[i] = 1; // used 表示在凸壳上
stk[++tp] = i;
}
int tmp = tp; // tmp 表示下凸壳大小
for (int i = n - 1; i > 0; --i)
if (!used[i]) {
// ↓求上凸壳时不影响下凸壳
while (tp > tmp && (p[stk[tp]] - p[stk[tp - 1]]) * (p[i] - p[stk[tp]]) <= 0)
used[stk[tp--]] = 0;
used[i] = 1;
stk[++tp] = i;
}
for (int i = 1; i <= tp; ++i) // 复制到新数组中去
h[i] = p[stk[i]];
int ans = tp - 1;

# 三维凸包

圆的反演:

反演中心为 O, 反演半径为 R, 若经过 O 的直线经过 P,P’, 且 OPxOP’ = R^2, 则称 P、P’关于 O 为反演