[学习笔记]半平面交

\[\color{red}{\textsf{小游者,真神人也,左马桶,右永神,会执利笔破邪炁,何人当之?}} \\ \begin{array}{|} \hline \color{pink}{\text{A small swimmer is a God.}} \\ \color{pink}{\text{The left toilet and the right eternal God}} \\ \color{pink}{\text{can break the evil energy with a sharp pen.}} \\ \color{pink}{\text{Who can resist him? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{green}{\text{小遊者は、神であり、左便器、右永神であり}} \\ \color{green}{\text{鋭いペンを持って真実を突き刺している。誰が彼に抵抗できるだろうか? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{lightblue}{\text{Petit voyageur, est Dieu aussi, toilettes gauche, Dieu éternel droit,}} \\ \color{lightblue}{\text{peut tenir un stylo tranchant pour briser le mal, qui devrait le faire?}} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{purple}{\text{Der Direktor ist wirklich ein Gott}} \\ \color{purple}{\text{mit einer Toilette links und Yongshen rechts}} \\ \color{purple}{\text{der einen spitzen Stift hält}} \\ \color{purple}{\text{um die Wahrheit zu durchdringen.}} \\ \color{purple}{\text{Wer kann ihm widerstehen? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{cyan}{\text{Ein kleiner Schwimmer ist ein Gott.}} \\ \color{cyan}{\text{Die linke Toilette und der rechte ewige Gott können }} \\ \color{cyan}{\text{die böse Energie mit einem scharfen Stift brechen.}} \\ \color{cyan}{\text{Wer sollte es sein?}} \\ \hline \end{array} \\ \color{red}{\textsf{对曰:“无人,狗欲当之,还请赐教!”}} \\ \newcommand\brak[1]{\left({#1}\right)} \newcommand\Brak[1]{\left\{{#1}\right\}} \newcommand\d[0]{\text{d}} \newcommand\string[2]{\genfrac{\{}{\}}{0pt}{}{#1}{#2}} \newcommand\down[2]{{#1}^{\underline{#2}}} \newcommand\ddiv[2]{\left\lfloor\frac{#1}{#2}\right\rfloor} \newcommand\udiv[2]{\left\lceil\frac{#1}{#2}\right\rceil} \newcommand\lcm[0]{\operatorname{lcm}} \newcommand\set[1]{\left\{{#1}\right\}} \newcommand\ceil[1]{\left\lceil{#1}\right\rceil} \newcommand\floor[1]{\left\lfloor{#1}\right\rfloor} \newcommand\rhs[1]{\;\text{Rhs}\;#1} \newcommand\lhs[1]{\;\text{Lhs}\;#1} \newcommand\Vec[1]{\vec{\mathbf{#1}}} \newcommand\rank[0]{\text{rank}} \newcommand\group[1]{\left\langle\right\rangle} \]

  芝士速补!

半平面交の定义

  一条直线将平面分为两个半平面,不妨假设一条直线 \(p_0p_1\) 的方向向量 \(\Vec v=p_1-p_0\)左边 是该直线对应的半平面。

  而一个点 \(p\)\(p_0p_1\) 半平面上即 \(p_0-p_1-p_2\) 向左拐,也即 \(\Vec v\times \overrightarrow{p_2-p_1}>0\).

  而半平面交就是很多个半平面的交集(点集、边集),显然,半平面交的结果会是一个凸区域。

求出半平面交

  有几种不同的做法。

增量法

  在线算法,每次加入一个半平面,就可以求出一个半平面交。由于平面无限,比较难处理,先放入一个很大的矩形使得整个平面变得有限,更方便处理。

  然后每给出一条有向直线(半平面),就计算它与前面所形成的半平面交的点集,并判断前面的半平面的点集有哪些在直线右边,如果在右边有扔掉,转而在该位置放下被扔掉点的前后两条边与直线的交点,如果在该直线右边,则加入点集,否则不加入。

  这种方法复杂度显然是 \(\mathcal O(n^2)\) 的,但是可以在算法结束后直接得到凸多边形的点集。

排序增量算法

  先将所有直线按照极角排序,然后按照极角从小到大加入直线,维护两个集合:边集和点集。下面用图演示这个过程多图警告!

  但是不是所有构建半平面交的时候都是这么理想,实际上有很多不合法情况,比如这种:

  我们将会先加入 \(AB\),然后是 \(FG\),最后是 \(CD\),但是我们发现,在 \(AB,FG\) 后,加入 \(CD\) 时,发现 \(H\)\(FG\) 都在 \(CD\) 的右边,说明 \(H\)\(CD\) 实际上都不会在下凸壳上,从对应集合中删去他们就行。(注意描述直线时字母顺序实际上给蕴含了该有向直线的方向)

  这个过程看上去和做凸包好像很想,那么我们能否用一个栈来构建?事实是,这个栈还得双向开口,如果有个这样的顺序:

  现有有向直线 \(IJ,AB,CD,EF,GH\),我们按照这个顺序加入直线,当加入到直线 \(GH\) 加入的时候,你会发现你想将 \(K\) 弹出去,但是 \(K\) 是点集中出现的第一个交点(直线 \(IJ,AB\) 的交点),因此栈需要双向开口。然后你会发现在处理完之后的栈会有两种情况:

  因为我们每次将双端队列两端不合法的情况去掉,因此最后只有可能出现情况 \(1,3\)(当然,情况 \(3\) 中的 \(A\) 点不在队列中),所以我们最后再用队首直线去判断一下队尾元素即可。

  在实际寻找半平面交的时候,应当注意一些边界情况:

  1. 交的区域为 \(0\) 且封闭,即退化为了一个点或者一条线段;
  2. 交的区域无限的情况(不封闭);
  3. 相邻直线夹角大于 \(\pi\)
  4. 相邻直线夹角刚好为 \(\pi\),这个时候交为一条直线区域,它可能和其他直线交出一条射线;
posted @ 2022-02-24 19:26  Arextre  阅读(91)  评论(0编辑  收藏  举报