计算几何 学习笔记
二维向量以及基础知识
二维向量是一条有向线段,只有长度和方向,因此可以用 \((x,y)\) 来表示一条向量从 \((0,0)\) 指向 \((x,y)\)。
对于一条向量 \(x\),\(|x|\) 表示模长,也就是长度。
对于 \(a=(x_1,y_1),b=(x_2,y_2)\):
模长:\(|a|=\sqrt{x_1^2+y_1^2}\)。
向量加:\(a+b=(x_1,y_1)+(x_2,y_2)=(x_1+x_2,y_1+y_2)\)。
数乘 \(az=(x_1,y_1)\times z=(zx_1,zy_1)\)。
点积:\(a\cdot b=|a||b|\cos \theta=x_1y_1+x_2y_2\),\(\theta\) 表示夹角。
叉积:\(a\times b=|a||b|\sin \{a,b\}=x_1y_2-x_2y_1\),$\sin {a,b} $ 表示从 \(a\) 转到 \(b\) 的夹角的 \(\sin\) 值。
容易发现这几个运算满足运算基本定理,结合律,交换律,分配率。
简单的代码实现:
struct Po {
db x, y;
};
Po operator+(Po x, Po y) { return {x.x + y.x, x.y + y.y}; }
Po operator-(Po x, Po y) { return {x.x - y.x, x.y - y.y}; }
db operator*(Po x, Po y) { return x.x * y.x + x.y * y.y; }
db operator/(Po x, Po y) { return x.x * y.y - x.y * y.x; }
判定两条线段相交
需要满足两个条件:
-
该线段作为对角线的矩形有交。
-
对于两条线段分别做以下判定:
一条线段是 \(ab\),另一条是 \(cd\),判定\(\overrightarrow{ca}\) 和 \(\overrightarrow{cb}\) 是否在 \(\overrightarrow{cd}\) 异侧。
求两向量夹角
判断一点是否在多边形内部
从这个点出发随机射出一条射线,与多边形边有奇数个交点就说明在其内部。
二维凸包
这个其实比较简单,容易发现 \(x\) 轴最小和最大的点一定在凸包上,因此求个上凸包和下凸包即可。
具体实现就是开个单调栈,从左向右把点加进去,需要满足斜率的单调。
如果有共线的情况还是比较阴间的。
旋转卡壳
省选前更新一下(
就是对于凸包求最远两点的距离,考虑用两条平行线去夹凸包,然后一起旋转,得到所有可能更新答案的方案。
凸包转的时候,一个点会在多条平行线的方案里,因此去考虑每条边,然后找到对面的点进行更新。
注意,线必须转完一圈,不能只转一半。
求最小矩形覆盖
相当于现在是找四个点,还是可以用一条边去找点对,然后左右两边用点积求即可。