<style> .reveal .slides { text-align: left; font-size:30px; } </style> # Geometry ---- - Convex Hull trick - Circle cover - Half Plane Intersection - Polygon Union - Minkowski sum --- ### Convex hull trick - $O(\log n)$ check point inside convex hull - $O(\log n)$ Find 2 tang pts on CH of a given outside point - $O(\log n)$ Find tangent points of a given vector - $O(\log n)$ Find intersection point of a given line ---- [link](https://github.com/jakao0907/CompetitiveProgrammingCodebook/blob/master/geometry/ConvexHulltrick2.cpp) - construct function - Convex(convex hull) ```cpp #define all(x) x.begin(), x.end() ``` ---- ## check point inside convex hull 給一個點,判斷是否在凸包內、外或者邊上 0: out, 1: on, 2: in ```cpp int inside(Pt p) ``` ---- ## NCPC 2021 --- E. Archery at the Summer Opymlic Camp 給定 $n$ 個凸包,每個凸包一層包一層, $q$ 筆詢問,每筆詢問給一個點,問在幾個凸包內 - $n, q\le 2\cdot 10^5$ ---- 模板可以 $O(\log n)$ 求出是否在某個凸包內,要求出包括幾個凸包可以二分搜。 ---- ## get tangent line of the point Given point $p$, return two point denote the tangent line from point $p$ to convex hull. ```cpp array<int, 2> tangent2(Pt p) ``` ![](https://hackmd.io/_uploads/ryzvjZ822.png) ---- The return point is the closest points. ![image](https://hackmd.io/_uploads/HJXxs6g5C.png) ---- ## NCPC 2020 --- M. The Summit from Where I Stand 給一個上半凸包為一座山,$q$ 筆詢問每筆詢問求在位置 $(x, y)$ 時,同時可以看到幾個點 ![](https://hackmd.io/_uploads/rkovaPioh.png =450x) 帶入模板找出公切線 index 即可。 ---- ## Find tangent points of a given vector return the idx of far/closer tangent point v (min cross value) ```cpp int tangent(Pt v, bool close = true) ``` ![image](https://hackmd.io/_uploads/HJJ9pTx50.png) ---- ## Find intersection point of a given line - return 2 index if intersection on the 2 points - return 1 index if intersection on the 1 point - return 0 index if no intersection intersection is on edge (i, next(i)) ```cpp vector<int> intersect(Line L) ``` ![](https://hackmd.io/_uploads/HJxz6Z822.png) --- ### Circle cover 給定 C 個圓,回傳一個陣列 Area, 其中 Area[i] 為至少包括 i 個圓的覆蓋面積 [link](https://github.com/jakao0907/CompetitiveProgrammingCodebook/blob/master/geometry/CircleCover.cpp) - init(int _c) - 總共 _c 個圓 - Circle c[ N ] - 填入圓的圓心&半徑 - solve() - 跑 CircleCover $O(n^2\log n)$ --- ### 半平面交 ### Half Plane Intersection ---- ### 半平面 每條直線能把平面切成兩半。 以方程式 $ax+by+c\le0$ 可以代表一個半平面。 ![](https://hackmd.io/_uploads/Hk6Z-z8h3.png =300x) $5x + 3y \le 5$ ---- ### 半平面交 半平面交為多個半平面的交集區域,通常為一個凸多邊形 ![](https://hackmd.io/_uploads/H1M-fGU2h.png =300x) - $5x + 3y - 5\le 0$ - $2 x-3 y + 7\le 0$ ---- 以下三個半平面圍成一個凸多邊形 ![](https://hackmd.io/_uploads/rJZjQM8n2.png =300x) - $5x + 3y - 5\le 0$ - $2 x-3 y + 7\le 0$ - $-2 x+0 y - 15\le 0$ ---- ## 模板 [[line define]](https://github.com/jakao0907/CompetitiveProgrammingCodebook/blob/master/geometry/definition.cpp) [[link]](https://github.com/jakao0907/CompetitiveProgrammingCodebook/blob/master/geometry/Half_plane_intersection.cpp) ```cpp vector<Pt> HPI(vector<Line>& L) ``` 傳入每條方程式的兩點方程式 (半平面為點 $st$ 往 $ed$ 的逆時針方向) 回傳值為形成的凸多邊形的頂點 vector (須保證結果為凸包) 半平面交沒有交集會回傳空的 vector $O(n\log n)$ ---- ## NCPC 2021 --- Overlapping Triangles $Q$ 筆詢問,每筆詢問給定兩個三角形,求交集面積 - $Q\le 80$ - $|x|, |y|\le 2^{32}$ ![](https://hackmd.io/_uploads/rkKxhzL2h.png =x350) ---- 題目等價於給定兩個凸多邊形,求兩個凸多邊形的交集 ---- 轉換為半平面就做完了 XD ![](https://hackmd.io/_uploads/rkMa6fL23.png =x350) --- ## Polygon Union 求 n 個多邊形的聯集面積 複雜度 O(n^2\log n) ---- [模板](https://github.com/jakao0907/CompetitiveProgrammingCodebook/blob/master/geometry/polyUnion.cpp) ```cpp double polyUnion(vector<vector<Pt>> py) ``` 傳入多個多邊形,每個多邊形為一個 vector\<Pt\> 回傳值為多邊形的聯集面積 ---- ## Polygon Cover Area[i] : area covered by at least i polygon $O(n^2\log n)$ [code](https://github.com/warner1129/CompetitiveProgrammingCodebook/blob/master/code/Geometry/UnionOfPolygons.cpp) --- ## Minkowski sum 對於給定的兩個點集合 $A$ 和 $B$。 Minkowski sum 為 $\{a + b\ |\ a\in A, b\in B\}$。 ![](https://hackmd.io/_uploads/HJFx07qFR.png =350x) ---- 將 Minkowski sum 視覺化,為一個凸包 A 繞著凸包 B 轉一圈。 並且兩個凸包 A 和 B 上的邊會在 Minkowski sum 中出現。 ![image](https://hackmd.io/_uploads/SyxxvR79KC.png =350x) ---- 幾個性質 - 兩個凸多邊形的 Minkowski sum,也會是凸多邊形 - P 和 Q 組成的 Minkowski sum 最多有 |P|+|Q| 個點。 - 在凸包 A 和 B 上的邊也會在 Minkowski sum 上出現。 ---- 模板 (Minkowski sum of convex polygons) 複雜度 $O(N)$ [link](https://github.com/jakao0907/CompetitiveProgrammingCodebook/blob/master/geometry/Minkowski_Sum.cpp) ```cpp vector<Pt> minkowski(vector<Pt> P, vector<Pt> Q) ``` 把多邊形 p 和 q 丟進去 minkowski,回傳的 vector 為組成的凸多邊形。 丟進去的多邊形要保證為照逆時針順序給,出來的也是逆時針順序的。 ---- ## Minimum Distance of two Convex Polygon 給兩個凸多邊形 $A$ 和 $B$,求出凸兩個多邊形的最近距離。 ---- 等價於從 $A$ 中找出一個點 $a$,$B$ 中找出一個點 $b$, 使得 $|a-b|$ 最小,也就是最靠近 (0, 0) 的點。 ---- 如果我們將 $B$ 的點都取負和 $A$ 去做 Minkowski sum。 也就是 Minkowski sum = $A$ + $(-B)$ ---- 求出來的集合為 $\{a - b\ |\ a\in A, b\in B\}$。 從中取出 $| a-b |$ 最小的值,即為兩個多邊形的最近距離。 --- ## Intersection of polygon and circle [圓 definition](https://github.com/jakao0907/CompetitiveProgrammingCodebook/blob/master/geometry/definition.cpp) [模板](https://github.com/jakao0907/CompetitiveProgrammingCodebook/blob/master/geometry/Intersection_of_polygon_and_circle2.cpp) ```cpp= ld PCIntersect(vector<Pt> v, Circle cir) ``` 傳入多邊形和圓,回傳交集面積 ---- ## Intersection of two circles 找出兩圓的交點 [模板](https://github.com/jakao0907/CompetitiveProgrammingCodebook/blob/master/geometry/Intersection_of_two_circles.cpp) 回傳 vector 為交點,若為空代表沒有交點。 ---- ## Tangent line of two circles 求出兩圓的切線 [模板](https://github.com/jakao0907/CompetitiveProgrammingCodebook/blob/master/geometry/Tangent_line_of_two_circles.cpp) sign1 傳入 1 求外公切線 sign1 傳入 -1 求內公切線 回傳值為 vector\<Line\>,對於每條切線 Line 第一個點為第一個圓切點位置 Line 第二個點為第二個圓切點位置 --- 今天教的幾何內容不多 但實際上需要花的整理時間是所有主題中最多的 建議每個模板都測過再放到各自的 codebook 如果沒測過不建議比賽中直接試(~~通常會直接試到比賽結束~~) ---- 幾何的內容如果現場推會需要不少時間 算是一個能先準備先賺到的主題 (軍備競賽) 可以多看別人的 codebook 去多放一些經典問題模板 但要記得修改成自己的幾何 definition 能用的樣子 但都要自己測過題目,需要額外一些經典題目可以跟 jakao 要 ---- 三角函數求切線等等幾何問題 如果遇到浮點數問題 記得在內建函數後面加 l $sin(x)\to sinl(x)$ $sqrt(x)\to sqrtl(x)$ $atan2(x)\to atan2l(x)$ 以避免不必要的 debug
{"title":"Geometry","description":"Convex Hull trick","contributors":"[{\"id\":\"19f09ccf-6b99-452f-971f-955cfc1657f3\",\"add\":6965,\"del\":837}]"}
    831 views
   Owned this note