计算几何个人学习笔记

update:

2026/6/13:
1.修改了不合理的序号
2.按照知乎修改了部分关于皮克定理的不正确内容
3.改正了一些炸掉的markdow

题单qwq

R圣的板

想区的饭子

参考文献:

此笔记仅为记录学习以及帮助复习 不包含任何利于理解的东西


零.向量是什么(会的直接忽略)

一、 向量的定义

在二维欧几里得空间 \(\mathbb{R}^2\) 中,平面向量 \(\vec{A}\) 被定义为一个有序实数对:

\[\vec{A} = (x, y) \in \mathbb{R}^2 \]

若已知空间中两点 \(P_1(x_1, y_1)\)\(P_2(x_2, y_2)\),则由 \(P_1\) 指向 \(P_2\) 的有向线段所确定的向量 \(\overrightarrow{P_1P_2}\) 表示为:

\[\overrightarrow{P_1P_2} = P_2 - P_1 = (x_2 - x_1, y_2 - y_1) \]


二、 向量的代数意义

对于任意向量 \(\vec{A} = (x, y)\)

1. 向量的模长 (Magnitude / Norm)

向量的二范数(几何长度)记作 \(|\vec{A}|\),其形式化定义为:

\[|\vec{A}| = \sqrt{x^2 + y^2} \]

2. 向量的辐角 (Direction Angle)

向量与正向 \(x\) 轴的夹角 \(\theta\) 的形式化定义为:

\[\theta = \text{atan2}(y, x) \in (-\pi, \pi] \]


三、 向量的代数运算

设已知向量 \(\vec{A} = (x_1, y_1)\)\(\vec{B} = (x_2, y_2)\),以及标量 \(k \in \mathbb{R}\)

1. 向量加法 (Vector Addition)

\[\vec{A} + \vec{B} = (x_1 + x_2, y_1 + y_2) \]

2. 向量减法 (Vector Subtraction)

\[\vec{B} - \vec{A} = (x_2 - x_1, y_2 - y_1) \]

3. 标量乘法 (Scalar Multiplication)

\[k\vec{A} = (kx_1, ky_1) \]


四、 板子

#include <bits/stdc++.h>
using namespace std;
struct Pt{
    double x,y;
};

double len,ang;
Pt a,b,c;

Pt add(Pt g1,Pt g2){
    Pt r;
    r.x=g1.x+g2.x;
    r.y=g1.y+g2.y;
    return r;
}

Pt sub(Pt g1,Pt g2){
    Pt r;
    r.x=g2.x-g1.x;
    r.y=g2.y-g1.y;
    return r;
}

Pt mul(Pt g1,double k){
    Pt r;
    r.x=g1.x*k;
    r.y=g1.y*k;
    return r;
}

double get_l(Pt g1){
    return sqrt(g1.x*g1.x+g1.y*g1.y);
}

double get_a(Pt g1){
    return atan2(g1.y,g1.x);
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    a.x=3.0;
    a.y=4.0;
    b.x=1.0;
    b.y=2.0;
    c=add(a,b);
    len=get_l(a);
    return 0;
}

一.向量计算

1. 数乘 (Scalar Multiplication)

  • 定义与形式化证明
    已知向量 \(\vec{v} = (x, y)\),实数 \(k\)。数乘运算将向量的每个分量扩大 \(k\) 倍:

\[k\vec{v} = (kx, ky) \]

证明:由相似三角形性质,若将直角三角形的斜边(向量长度)放大 \(k\) 倍,则其直角边(\(x\)\(y\) 轴的分量)亦必然按比例放大 \(k\) 倍。

  • 几何意义:保持向量方向不变(\(k>0\))或完全相反(\(k<0\)),改变向量的长度。

2. 点乘 / 内积 (Dot Product)

  • 形式化证明
    已知 \(\vec{A} = (x_1, y_1)\)\(\vec{B} = (x_2, y_2)\)。点乘定义为:

\[\vec{A} \cdot \vec{B} = x_1 x_2 + y_1 y_2 \]

同时满足几何定理:\(\vec{A} \cdot \vec{B} = |\vec{A}||\vec{B}|\cos\theta\)\(\theta\) 为夹角)。

证明(利用余弦定理)
考虑以原点 \(O\)、点 \(A(x_1, y_1)\)、点 \(B(x_2, y_2)\) 构成的三角形。边 \(AB\) 的长度平方为:

\[|AB|^2 = (x_1 - x_2)^2 + (y_1 - y_2)^2 = x_1^2 + y_1^2 + x_2^2 + y_2^2 - 2(x_1 x_2 + y_1 y_2) \]

根据三角形余弦定理:

\[|AB|^2 = |\vec{A}|^2 + |\vec{B}|^2 - 2|\vec{A}||\vec{B}|\cos\theta \]

由于 \(|\vec{A}|^2 = x_1^2 + y_1^2\)\(|\vec{B}|^2 = x_2^2 + y_2^2\),两式对照相减立刻得到:

\[|\vec{A}||\vec{B}|\cos\theta = x_1 x_2 + y_1 y_2 \]

  • 几何意义:用于计算夹角及判断正交性。若点乘 \(>0\) 夹角为锐角;\(<0\) 为钝角;\(=0\) 则两向量垂直。

3. 叉乘 / 外积 (Cross Product)

  • 形式化证明
    二维向量的叉乘定义为行列式的值:

\[\vec{A} \times \vec{B} = \begin{vmatrix} x_1 & x_2 \\ y_1 & y_2 \end{vmatrix} = x_1 y_2 - y_1 x_2 \]

同时满足几何定理:\(\vec{A} \times \vec{B} = |\vec{A}||\vec{B}|\sin\theta\)

证明(利用三角函数展开)
\(\vec{A}\) 的极角为 \(\alpha\)\(\vec{B}\) 的极角为 \(\beta\),则 \(\theta = \beta - \alpha\)
代入极坐标成分:\(x_1 = |\vec{A}|\cos\alpha, y_1 = |\vec{A}|\sin\alpha\)\(x_2 = |\vec{B}|\cos\beta, y_2 = |\vec{B}|\sin\beta\)

\[x_1 y_2 - y_1 x_2 = |\vec{A}||\vec{B}|(\cos\alpha\sin\beta - \sin\alpha\cos\beta) \]

根据正弦和差化积公式 \(\sin(\beta - \alpha) = \sin\beta\cos\alpha - \cos\beta\sin\alpha\),上式即:

\[x_1 y_2 - y_1 x_2 = |\vec{A}||\vec{B}|\sin\theta \]

  • 几何意义:其绝对值是以 \(\vec{A}, \vec{B}\) 为邻边的平行四边形的面积。其正负号表达了 \(\vec{B}\) 相对 \(\vec{A}\) 的顺逆时针旋转走向。

二、 直线、线段与点的位置关系

1. 判断点在直线的哪一边

  • 证明
    已知直线由有向线段 \(P_1(x_1, y_1) \to P_2(x_2, y_2)\) 唯一确定,判断点 \(Q(x_3, y_3)\) 的方位。
    构造向量 \(\vec{A} = \overrightarrow{P_1 P_2} = (x_2 - x_1, y_2 - y_1)\)\(\vec{B} = \overrightarrow{P_1 Q} = (x_3 - x_1, y_3 - y_1)\)
    计算叉积 \(D = \vec{A} \times \vec{B}\)

证明:由叉积性质 \(\vec{A} \times \vec{B} = |\vec{A}||\vec{B}|\sin\theta\)

  • \(\theta \in (0, \pi)\),则 \(\sin\theta > 0 \implies D > 0\),点 \(Q\)\(P_1 P_2\)逆时针方向(左侧)
  • \(\theta \in (-\pi, 0)\),则 \(\sin\theta < 0 \implies D < 0\),点 \(Q\)\(P_1 P_2\)顺时针方向(右侧)
  • \(D = 0\),则 \(\sin\theta = 0\),三点共线

2. 判断两线段是否相交 (跨立实验)

  • 形式化证明
    线段 \(AB\)\(CD\) 相交的充要条件是它们彼此跨立对方。即:
  1. \(C\)\(D\) 在直线 \(AB\) 的两侧:\((\overrightarrow{AB} \times \overrightarrow{AC}) \times (\overrightarrow{AB} \times \overrightarrow{AD}) \le 0\)
  2. \(A\)\(B\) 在直线 \(CD\) 的两侧:\((\overrightarrow{CD} \times \overrightarrow{CA}) \times (\overrightarrow{CD} \times \overrightarrow{CB}) \le 0\)
  3. 证明:如果线段相交,直线 \(AB\) 必然将线段 \(CD\) 斩断为两部分。这意味着点 \(C\) 在直线 \(AB\) 的一边(叉积符号为正),而点 \(D\) 必须在直线 \(AB\) 的另一边(叉积符号为负)。两者叉积相乘乘积必然 \(\le 0\)。同理,对直线 \(CD\) 检验 \(AB\) 顶点亦然。

3. 求两条直线的交点

  • 证明(利用有向面积比)
    已知第一条直线通过 \(A, B\),第二条直线通过 \(C, D\)。设交点为 \(P\)

证明:过 \(C\)\(D\) 分别向直线 \(AB\) 作垂线,垂线段长度分别为 \(h_1, h_2\)
由相似三角形可知:\(\frac{|CP|}{|PD|} = \frac{h_1}{h_2}\)
而三角形 \(ABC\) 的面积 \(S_{ABC} = \frac{1}{2}|AB|h_1\),三角形 \(ABD\) 的面积 \(S_{ABD} = \frac{1}{2}|AB|h_2\)
因此:\(\frac{|CP|}{|PD|} = \frac{S_{ABC}}{S_{ABD}}\)。利用叉积的有向面积,我们可以精确得到点 \(P\) 分有向线段 \(CD\) 的比值。
代入分点坐标公式,交点 \(P\) 的位置为:

\[P = C + \overrightarrow{CD} \times \frac{\overrightarrow{AB} \times \overrightarrow{AC}}{\overrightarrow{AB} \times \overrightarrow{AC} - \overrightarrow{AB} \times \overrightarrow{AD}} \]


三、 圆与多边形高阶算法

1. 求圆过圆外一点的切线

  • 证明
    已知圆心 \(O(x_0, y_0)\),半径 \(R\),圆外一点 \(P(x_1, y_1)\)。求切点 \(T\)

证明:直角三角形 \(\triangle OTP\) 中,\(\angle OTP = 90^\circ\)
斜边长度 \(d = |OP| = \sqrt{(x_1 - x_0)^2 + (y_1 - y_0)^2}\)
切线长 \(L = |PT| = \sqrt{d^2 - R^2}\)
切角 \(\alpha = \arcsin(R / d)\)
求出向量 \(\overrightarrow{OP}\) 的极角 \(\beta = \text{atan2}(y_1 - y_0, x_1 - x_0)\)
则两个切点相对于圆心的极角分别为 \(\beta + \alpha\)\(\beta - \alpha\)
切点坐标为 \((x_0 + R\cos(\beta \pm \alpha), y_0 + R\sin(\beta \pm \alpha))\)

2. 判断点是否在多边形内部 (射线法)

  • 证明
    从待测试点 \(Q\) 发出一条任意方向的射线(通常水平向右)。

证明:根据若尔当曲线定理 (Jordan Curve Theorem),一条闭合的多边形边界将平面精确切分为内部和外部。从外部无穷远处沿射线移动到点 \(Q\),每穿过一次多边形的边,就发生一次“内部 \(\leftrightarrow\) 外部”的状态切换。

  • 穿过奇数次:点 \(Q\) 在多边形内部
  • 穿过偶数次:点 \(Q\) 在多边形外部

3. 三角形与任意多边形的面积

  • 形式化证明(鞋带公式 / 鞋带定理)
    对于顶点依次为 \(P_0, P_1, \dots, P_{n-1}\) 的任意多边形,其有向面积 \(S\) 为:

\[S = \frac{1}{2} \sum_{i=0}^{n-1} (P_i \times P_{i+1}) = \frac{1}{2} \sum_{i=0}^{n-1} (x_i y_{i+1} - y_i x_{i+1}) \]

(其中 \(P_n = P_0\)

证明:在平面内任取一点作为原点 \(O\)。将多边形顶点与 \(O\) 连线,划分成 \(n\) 个有向三角形 \(\triangle O P_i P_{i+1}\)
每个三角形的有向面积为 \(\frac{1}{2} (\overrightarrow{OP_i} \times \overrightarrow{OP_{i+1}})\)
当多边形边界逆时针包围原点时,多边形外部的三角面积会在求和中正负抵消,最终精确收敛留有多边形的净面积。

4. 求多边形内部整点数量 (皮克定理)

  • 证明

皮克定理 (Pick's Theorem):对于顶点全在格点(整数坐标点)上的简单多边形,其面积 \(S\)、内部整点数 \(I\)、边界上的整点数 \(B\) 满足完美的线性代数关系:

\[S = I + \frac{B}{2} - 1 \implies I = S - \frac{B}{2} + 1 \]

证明概要:可以证明该定理在单位正方形下成立(\(S=1, B=4, I=0 \implies 1 = 0 + 2 - 1\) 正确)。由于任何格点多边形都可以拆分成若干个格点三角形,且此代数式在多边形拼接时具有拓扑加和不变性(共有边上的整点会从 \(B\) 变为 \(I\) 相互抵消),故定理对一切格点多边形普适。

  • 如何求 \(B\):利用有理数几何性质,一条从 \((x_1, y_1)\)\((x_2, y_2)\) 的线段,其边界上的整点数(不含起点)等于 \(\gcd(|x_1 - x_2|, |y_1 - y_2|)\)

四、凸包

1、 凸包的形式化定义

在二维实数欧几里得空间 \(\mathbb{R}^2\) 中,给定一个包含 \(n\) 个点的有限点集 \(S = \{P_1, P_2, \dots, P_n\}\)
点集 \(S\)凸包(记作 \(\text{CH}(S)\))定义为包含 \(S\) 的所有凸组合的最小集合,即:

\[\text{CH}(S) = \left\{ \sum_{i=1}^n \alpha_i P_i \ \middle|\ \sum_{i=1}^n \alpha_i = 1, \ \alpha_i \ge 0 \right\} \]

在几何上,\(\text{CH}(S)\) 是一个凸多边形,其顶点属于 \(S\),且 \(S\) 中的所有点要么在该多边形的边界上,要么在其内部。


2、 核心判定工具:有向面积(叉积)

对于平面上的三个有序点 \(O, A, B\),通过构造向量 \(\overrightarrow{OA} = A - O\)\(\overrightarrow{OB} = B - O\),定义其二维叉积(有向面积的 2 倍)为:

\[\text{crs}(O, A, B) = \overrightarrow{OA} \times \overrightarrow{OB} = (A.x - O.x)(B.y - O.y) - (A.y - O.y)(B.x - O.x) \]

根据叉积的代数性质,转向判定规则如下:

  • \(\text{crs}(O, A, B) > 0 \iff\)\(O \to A\) 再到 \(B\) 满足逆时针旋转(左拐)
  • \(\text{crs}(O, A, B) < 0 \iff\)\(O \to A\) 再到 \(B\) 满足顺时针旋转(右拐)
  • \(\text{crs}(O, A, B) = 0 \iff\) \(O, A, B\) 三点共线

3、 算法一:Andrew 算法(Monotone Chain)

Andrew 算法通过按水平坐标排序,将凸包分为下凸壳(Lower Hull)上凸壳(Upper Hull)分别构建。

1. 算法流程

  1. 将点集 \(S\) 按照 \(x\) 坐标升序排序,若 \(x\) 相同则按 \(y\) 坐标升序排序。
  2. 构建下凸壳:从左到右遍历排序后的点,用单调栈维护顶点。对于新加入的点 \(P_i\),若栈顶两点与 \(P_i\) 的转向关系满足 \(\text{crs}(S_{top-1}, S_{top}, P_i) \le 0\)(非左拐),则将栈顶元素弹出,重复此过程直到满足左拐,再将 \(P_i\) 入栈。
  3. 构建上凸壳:从右到左倒序遍历点集,重复上述单调栈维护逻辑。

2. 证明

证明(反证法)
假设按照上述规则构建的下凸壳中存在一个局部凹陷。这意味着存在连续三点 \(A, B, C\),使得 \(\text{crs}(A, B, C) \le 0\)
由于算法在遍历到点 \(C\) 时,会检查栈顶两点(此时即为 \(A, B\))与 \(C\) 的有向面积。若满足 \(\text{crs}(A, B, C) \le 0\)while 循环中的 st.pop_back() 必然会被执行,从而将点 \(B\) 从栈中弹出。
因此,最终留在栈中的任意连续三点必然严格满足 \(\text{crs}(S_{top-1}, S_{top}, P_i) > 0\)(全左拐关系),在数学上确保了多边形的局部与全局凸性。同样地,由于排序后起点和终点具有极值性,它们必然属于拓扑边界,结合上凸壳的逆向扫描,确保了生成的闭合多边形包含所有点。


4、 算法二:Graham Scan 算法

Graham Scan 则是基于极角排序(Polar Angle Sort)的单调栈扫描算法。

1. 算法流程

  1. 选择点集 \(S\)\(y\) 坐标最小的点作为基准点 \(P_0\)(若 \(y\) 相同则取 \(x\) 最小者)。
  2. 将其余所有点按照相对于 \(P_0\) 的极角 \(\theta = \text{atan2}(P_i.y - P_0.y, P_i.x - P_0.x)\) 顺时针/逆时针排序。
  3. 用单调栈正向遍历排序后的点集,同样利用 \(\text{crs}(S_{top-1}, S_{top}, P_i) \le 0\) 的退化判定弹出凹点。

2. 证明

证明概要
由于基准点 \(P_0\) 处于点集的绝对左下角,其余点相对于 \(P_0\) 的极角严格分布在 \([0, \pi)\) 区间内。
按极角序升序排列后,连接 \(P_0\) 与各顶点的射线 \(\overrightarrow{P_0P_i}\) 随索引 \(i\) 的增加单调向左摆动。
当单调栈向前推进时,若出现 \(\text{crs}(S_{top-1}, S_{top}, P_i) \le 0\),由于 \(P_i\) 位于比 \(S_{top}\) 更靠左的射线上,该几何状态表明 \(S_{top}\) 掉入了由 \(P_0, S_{top-1}, P_i\) 构成的闭合三角形内部,成为了非边界点。将其弹出栈并保持全行程左拐,最终在极角单调转完一圈回到 \(P_0\) 时,栈内保存的序列即构成完备的全局凸壳边界。


posted @ 2026-09-23 20:18  想想ovo  阅读(1)  评论(0)    收藏  举报