跳到主要内容

凸包算法 (Convex Hull)

给定平面上的一组点,能够包含所有这些点的最小凸多边形称为凸包(Convex Hull)。在计算几何中,凸包算法是许多复杂问题的预处理基石。


1. 形式化定义与拓扑性质

凸包的等价定义
  1. 集合论定义:包含点集 SS 的所有凸集的交集 CH(S)={KSK is convex}\text{CH}(S) = \bigcap \{ K \supseteq S \mid K \text{ is convex} \}
  2. 组合定义SS 中所有点的凸组合构成的集合 {i=1nλiPiλi=1,λi0}\{ \sum_{i=1}^n \lambda_i P_i \mid \sum \lambda_i = 1, \lambda_i \ge 0 \}

1.1 Andrew 算法(单调链法)的单调性证明

Andrew 算法通过将凸包分解为**上凸壳(Upper Hull)下凸壳(Lower Hull)**进行构建。

证明:拓扑单调性与正确性

  1. 全序单调性:首先按 xx 坐标升序(xx 相同时按 yy 升序)对点集 SS 排序。排序后的序列 P1,P2,,PnP_1, P_2, \dots, P_n 确保了 P1P_1PnP_n 必为凸包上的顶点(极点)。
  2. 局部凸性维持:在构建下凸壳时,维护一个栈 HH。对于新点 PiP_i,若 Hk2Hk1×Hk1Pi0\vec{H_{k-2}H_{k-1}} \times \vec{H_{k-1}P_i} \le 0,说明 Hk1H_{k-1} 相对于 Hk2H_{k-2}PiP_i 构成的链发生了“右转”或共线。
    • 代数含义:叉积 0\le 0 意味着 Hk1H_{k-1} 落在向量 Hk2Pi\vec{H_{k-2}P_i} 的右侧。
    • 单调性:由于 xHk2<xHk1<xPix_{H_{k-2}} < x_{H_{k-1}} < x_{P_i},弹出 Hk1H_{k-1} 后连接 Hk2H_{k-2}PiP_i 必然会扩大下方覆盖区域且保持下凸性。
  3. 收敛性:扫描完成后,下凸壳从 P1P_1 单调增加至 PnP_n(按 xx 轴正向),上凸壳从 PnP_n 单调减少回 P1P_1(按 xx 轴负向)。两链合围形成的区域包含了 SS 的所有点,且由于每一步都强制“左转”(Left-turn),结果必为凸集。

2. 拓扑一致性验证 (Topological Consistency)

在构建凸包时,退化情况可能破坏拓扑结构:

退化拓扑判定
  • 重合点:必须通过 unique 去重,否则在叉积计算中会出现零向量,导致 sign 判定失效。
  • 垂直退化:若所有点 xx 坐标相同,排序后它们将按 yy 坐标排列。下凸壳将包含所有点,上凸壳则会立即退回起点。
  • 一致性校验逻辑
    // 拓扑一致性:结果点数应 >= 3 (除非所有点共线)
    if (hull.size() < 3 && pts.size() >= 3) {
    // 捕获退化为线段的情况
    }
共线点保留策略
  • 严格凸包:使用 sign(cross(...)) <= 0 弹出。此时凸包边上不含除顶点外的点。
  • 非严格凸包:使用 sign(cross(...)) < 0 弹出。此时共线点会被保留。 边界注意:在处理上凸壳时,扫描起始位置应为 n2n-2,且最后的 resize(k-1) 逻辑需确保不误删首尾重复点。

3. 教材级核心代码实现 (C++)


4. 经典推导与练习库 (Exercises)

例题 1:动态凸包判定 - 二分加速证明

题目描述:给定一个逆时针序凸多边形,判断点 PP 是否在内部。 推导: 对于凸多边形 V0,V1,,Vn1V_0, V_1, \dots, V_{n-1},取 V0V_0 为原点。点 PP 在多边形内当且仅当:

  1. PP 落在角 Vn1V0V1\angle V_{n-1}V_0V_1 之间。
  2. 找到 Vi,Vi+1V_i, V_{i+1} 使得 PP 落在角 ViV0Vi+1\angle V_iV_0V_{i+1} 内。
  3. PP 在有向边 ViVi+1\vec{V_iV_{i+1}} 的左侧。 由于 ViV0Vi+1\angle V_iV_0V_{i+1}ii 单调递增,步骤 2 可通过二分查找在 O(logn)O(\log n) 完成。
Check Solution
练习 1:闵可夫斯基和 (Minkowski Sum)

题目描述:计算两个凸多边形 A,BA, B 的向量和 C={a+baA,bB}C = \{ a+b \mid a \in A, b \in B \}定理:两个凸多边形的闵可夫斯基和仍为凸多边形,且其边集为 AABB 的边集按极角排序后的合并。 应用:判断两个凸多边形是否相交。AB    0ABA \cap B \neq \emptyset \iff 0 \in A - B

Check Solution
练习 2:动态凸包维护 (Online Convex Hull)

题目描述:支持动态插入点并实时查询凸包面积。 思路:使用 std::set 按极角或坐标维护凸包顶点。插入点时,通过 lower_bound 找到邻居,利用叉积判断是否需要弹出受影响的旧顶点。

Check Solution

提示:维护上凸壳与下凸壳的两个 std::set<Point>。插入点 PP 时,若 PP 已在壳内则跳过;否则插入并向两侧通过 while 循环删除非凸点。


🎯 模块导航