cunzai_zsy0531

关注我

WC2022

Post time: 2022-01-23 09:49:47

Day 1

第二课堂:计算几何

前置知识:

向量叉积:\(\overrightarrow{AB}\times \overrightarrow{CD}=x_1y_2-x_2y_1\)

一、多边形面积

设多边形顶点逆时针记为 \(p_1,p_2,\ldots,p_n\),任选一个辅助点 \(O\),记 \(\overrightarrow{v_i}=\overrightarrow{Op_i}\),那么

\[S=\frac{1}{2}|\sum_{i=1}^n \overrightarrow{v_i}\times \overrightarrow{v_{(i\bmod n)+1}}| \]

二、切比雪夫距离以及其与曼哈顿距离的转化

\((x_1,y_1)\)\((x_2,y_2)\) 两点之间的切比雪夫距离为 \(\max(|x_1-x_2|,|y_1-y_2|)\)

\[\begin{aligned} d(A,B)&=|x_1-x_2|+|y_1-y_2|\\ &=\max\{x_1-x_2+y_1-y_2,x_1-x_2+y_2-y_1,x_2-x_1+y_1-y_2,x_2-x_1+y_2-y_1\}\\ &=\max\{|(x_1+y_1)-(x_2+y_2)|,|(x_1-y_1)-(x_2-y_2)|\} \end{aligned} \]

也就是说,\((x_1,y_1)\)\((x_2,y_2)\) 的曼哈顿距离等于 \((x_1+y_1,x_1-y_1)\)\((x_2+y_2,x_2-y_2)\) 的切比雪夫距离。

同理可以推出,\((x_1,y_1)\)\((x_2,y_2)\) 之间的切比雪夫距离等于 \((\frac{x_1+y_1}{2},\frac{x_1-y_1}{2})\)\((\frac{x_2+y_2}{2},\frac{x_2-y_2}{2})\) 之间的曼哈顿距离。

三、判断 \(Q\) 在线段 \(P_1P_2\) 上的方法:

  1. \(\overrightarrow{P_1Q}\times\overrightarrow{P_1P_2}=0\),在直线上
  2. \(Q\) 在以 \(P_1,P_2\) 为对角顶点的矩形内。

四、判断两线段是否相交

  1. 快速排斥试验

\(P_1P_2\)\(Q_1Q_2\) 不相交,那么以这两个线段为对角线的矩形不相交。

  1. 跨立实验

如果两线段相交,那么两线段互相跨立对方,即

\[(\overrightarrow{Q_1P_1}\times \overrightarrow{Q_1Q_2})\cdot (\overrightarrow{Q_1Q_2}\times \overrightarrow{Q_1P_2})\geq 0 \]

两实验都不是等价的,两个必要条件可以拼成等价条件。

另外:判断线段和直线相交,只需要线段跨立直线即可。

五、判断点是否在多边形中

从这个点向左做射线 \(L\),在无穷远处开始向右扫,到这个点的时候统计与多边形边界的交点个数,奇数就在多边形内,偶数就不在多边形内。

但是会有一些特殊情况,所以需要做以下规定:

  1. 多边形水平边不考虑。
  2. 对于顶点和 \(L\) 相交的情况,如果该顶点是其所属边上纵坐标较大的顶点,则计数,否则忽略。
  3. 对于 \(P\) 在多边形边上的情形,直接判断属于。

六、判断线段是否在多边形内

求出所有与线段相交的多边形顶点。

按照 \(x\) 为第一关键字,\(y\) 为第二关键字将坐标排序,这样考虑相邻两点,如果任意相邻两点的中点都在多边形内,那么整个线段都在多边形内。

七、判断点到线段的最近点

考虑线段平行于坐标轴的情况和其余一般情况。

一般情况的话,就求出垂足坐标,看这个点是否在线段上,如果不在的话对两个端点取个距离小的就行了。

另:点到折线的最近点就对每个段都求一个最近点,取最近的就行了。

在求交点的时候,注意直线没有斜率、斜率为零、点在圆内等特殊情况。

八、二维凸包

(1)Andrew 算法

排序以 \(x\) 第一关键字,\(y\) 第二关键字,拿最小的元素和最大的元素从前往后和从后往前维护两个逆时针单调栈,一直只能向左拐,不能向右拐(左右拐就用叉积的正负判断即可)。时间复杂度为排序的 \(O(n\log n)\)

(2)Graham 算法

找到最左下的点,其他点按照极角排序,从小到大加入之后判断是不是形成了凹多边形即可。

九、旋转卡壳

考虑求凸包上每条边对应的最远点,首先考虑可以把距离转化为三角形面积,三角形面积可以用叉积求,逆时针旋转边的时候,最远点也逆时针旋转,并且对于一条固定的边,距离沿逆时针方向的函数是单增的。这样直接双指针扫过去然后更新答案,可以求凸包直径(点之间最大距离)。

十、半平面交

算法:S&l 算法

将所有半平面的向量按照极角排序,先把所有半平面都弄到向量的同一边,删除极角相同的不优的向量。接下来考虑,每次加入一个向量,考虑之前的所有交点,如果这个交点在向量非半平面的那一侧,那么形成这个交点的向量就没用了,这里可以根据单调性直接维护单调队列,从队尾和队头开始弹即可。注意这里必须先弹队尾再弹队头。

十一、平面最近点对

考虑一个分治算法:

首先将所有点按照 \(x\) 第一关键字,\(y\) 第二关键字排序。

每次分治分别考虑前后一半的点内部最近点对,设中间点为 \(p_m(m=\lfloor\frac{n}{2}\rfloor)\),两内部最近点对距离 \(h\),考虑如何合并:

首先拿出可能出现最近点对的点集 \(B=\{p_i||x_{p_i}-x_m|<h\}\),对这些点按照 \(y\) 坐标再次排序,然后考虑每个点 \(p_i\) 的邻域 \(C(p_i)\),其中 \(C(p_i)=\{p_j|y_{p_i}-h<y_{p_j}\leq y_{p_i}\}\)

可以证明,\(C(p_i)\) 的大小很小,最大为 \(7\)

然后 \(y\) 的排序可以和分治过程一起归并,这样总的复杂度为 \(O(n\log n)\)

补充:

求两条直线的交点:

由于斜率的特殊性,在处理的时候总是需要特殊讨论,所以在这里对于一条直线,采用记录直线上一点和直线方向向量的形式。

假设两条直线的方向向量为 \(\overrightarrow{a},\overrightarrow{b}\),两条直线两点之间的向量为 \(\overrightarrow{u}\),考虑

\[T=\frac{|\overrightarrow{u}\times \overrightarrow{b}|}{|\overrightarrow{a}\times \overrightarrow{b}|}=\frac{|\overrightarrow{u}|\sin \theta_1}{|\overrightarrow{a}|\sin \theta_2} \]

后面那个东西去掉分母上的 \(\overrightarrow{a}\) 其实就是交点离 \(a\) 那条直线上那点的距离,所以 \(T\overrightarrow{a}\) 就是连带着方向向量一起的,加过去就得到交点了。

posted @ 2022-04-25 19:19  cunzai_zsy0531  阅读(156)  评论(0编辑  收藏  举报