核心概述:用 Andrew 单调链算法在 O(n log n) 时间构建点集凸包(逆时针顺序),排除边上共线中间点。

Returns a vector of the points of the convex hull in counter-clockwise order. Points on the edge of the hull between two other points are not considered part of the hull. Time: O(n \log n) Status: stress-tested, tested with kattis:convexhull

展开阐述:

  • 定义与背景

    • 凸包:包含所有点的最小凸多边形,其顶点来自输入点集的极点。
    • 典型场景:最远点对(028-几何-凸包直径)、点集可视边界、碰撞外框、GIS 边界估计等。
    • 接口(据实现):
      • vector

        convexHull(vector

        pts),P=Point;若 sz(pts) ≤ 1,直返 pts。

  • 核心算法流程(Andrew Monotone Chain)

    1. 排序:按 x 再 y 的字典序排序点集。
    2. 构建下链:依次扫描,将当前点 p 推入前,用 cross(h[t-2], h[t-1], p) ≤ 0 时弹栈,确保“左转”保持凸性。
    3. 构建上链:对排序后的点序反向重复上述过程。
    4. 合并:拼接上下链,去掉最后一个重复端点;若 t2 且 h[0]h[1],减一避免重复。
    5. 输出:逆时针顺序顶点,排除边上共线中间点(通过 ≤0 判定)。
  • 复杂度与边界条件

    • 复杂度:排序 O(n log n),扫描 O(n),总计 O(n log n)。
    • 多重点与共线:
      • 若存在重复点,排序后相邻,弹栈规则不受影响;输出不含重复。
      • 共线点置于边上时被排除(严格凸包顶点),若需保留边上所有点,将判定改为 <0。
    • 全部共线:结果包含两端点(或实现细节下的最小端点集);按具体实现可能仅返回两个端点。
    • 坐标范围:P=Point,叉积可能超 64 位,必要时以内置 128 位计算。
  • 实现细节与常见坑

    • 方向与顺序:输出为 ccw;若需 cw,可反转输出。
    • 比较运算:排序与去重需一致的比较器;若要先 unique 去重,当心稳定性。
    • 判定边界:cross 判定采用 ≤0 使得共线中点被弹出;修改为 <0 可保留共线点。
    • 小规模:n ≤ 1 直接返回;n=2 返回两个点(按实现可能去重)。
  • 变体与扩展

    • 维护动态凸包:需要复杂数据结构(不在本实现范围)。
    • 3D 凸包:见017-几何-三维凸包
    • 半平面交获取凸多边形:与凸包问题互补。
  • 正确性要点与不变式

    • 栈内顶点始终保持凸性与单调性;每次仅在右转/共线时弹出破坏凸性的点。
    • 上下链覆盖全局极点,拼接后为完整凸边界。
  • 对比与取舍

    • 与 Graham 扫描法相比:实现更简洁,排序后线性扫描;二者复杂度相当。
    • Jarvis 行走(礼物包装):在极端情况下 O(nh),当 h(凸包顶点数)很小时可能更优。

关联节点