计算几何 学习笔记

二维向量以及基础知识

二维向量是一条有向线段,只有长度和方向,因此可以用 \((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}\) 异侧。

求两向量夹角

\[\theta=\text{acos}( \frac{a\cdot b}{|a||b|}) \]

判断一点是否在多边形内部

从这个点出发随机射出一条射线,与多边形边有奇数个交点就说明在其内部。

二维凸包

这个其实比较简单,容易发现 \(x\) 轴最小和最大的点一定在凸包上,因此求个上凸包和下凸包即可。

具体实现就是开个单调栈,从左向右把点加进去,需要满足斜率的单调。

如果有共线的情况还是比较阴间的。

洛谷数据太水,这是参考实现

旋转卡壳

省选前更新一下(

就是对于凸包求最远两点的距离,考虑用两条平行线去夹凸包,然后一起旋转,得到所有可能更新答案的方案。

凸包转的时候,一个点会在多条平行线的方案里,因此去考虑每条边,然后找到对面的点进行更新。

注意,线必须转完一圈,不能只转一半。

参考代码

求最小矩形覆盖

相当于现在是找四个点,还是可以用一条边去找点对,然后左右两边用点积求即可。

posted @ 2023-03-06 10:17  houzhiyuan  阅读(26)  评论(0编辑  收藏  举报