閔可夫斯基和 學習筆記

Cyan_wind發表於2024-08-02

閔可夫斯基和

定義兩個凸包 \(A,B\) 的閔可夫斯基和 \(C=\{a+b\mid a\in A,b\in B\}\) 。就是從原點向其中一個凸包連出的向量,平移到另一個凸包上的每一個點,最後構成的圖形即為兩個凸包的閔可夫斯基和。其中的第一個圖形可以看做被縮到了原點,\(C\) 中右下角(這裡是指先是 \(y\) 座標最小,再是 \(x\) 座標最小的點)的點是 \(A,B\) 中兩個右下角的點的座標之和。

求法

對於兩個凸包的情況,我們可以手模發現,最終形成的凸包 \(C\) 的每一條邊都是凸包 \(A,B\) 中的一條邊,可以用平行四邊形來證明。由於在凸包上的每一條邊,從最下面的那一條邊開始,按照逆時針順序,它們的極角是遞增的。所以我們可以將 \(A,B\) 上的邊依次比較極角,然後加入 \(C\) 中,從起始點開始每次加上那個邊表示的向量。

對於多個凸包的情況,我們可以將所有的邊放到一起進行排序,最後一起處理。

求凸包

(由於自己總是求不對凸包,這裡寫一下)

通常是先求出右下角的點,然後按照以該點為原點的其他點的極角序加入凸包。這裡如果使用 \(atna2(y,x)\) 的話,要注意精度問題;另一種判斷方法是用叉積:若 \(\vec{AB}\times\vec{AC}<0\) ,則 \(\vec{AC}\)\(\vec{AB}\) 的順時針方向(\(\vec{AB}\) 所在的直線的右邊,視角為向量的方向);若 \(>0\) ,則在逆時針方向;若 \(=0\) ,則兩個向量共線。這裡要注意的是由於極角是到 \(x\) 軸的正半軸,所以要先比較兩個向量是否同在 \(x\) 軸的上方或下方,然後再判斷;如果兩個向量方向相同,則要先加入距離右下角的點最遠的的,因為一般情況下我們會將凸包上所有三點共線的點刪掉,所以要這樣做來防止刪掉了我們要求的凸包上的點。

(防止自己記不住,再寫一遍:\(\vec{A}\times\vec{B}=A.x*B.y-A.y*B.x\)

由於在凸包上的連續三個點 \(P_1,P_2,P_3\) 按照逆時針排序的話,它們是滿足 \(\vec{P_1P_2}\times\vec{P_2P_3}\ge0\) 的,由於我們不要三點共線上的點,所以一般將 \(=\) 去掉。構建時維護一個棧,每次判斷棧頂的下一位、棧頂和要加入的點是否滿足條件,不滿足就彈棧。

練習題

P8101 [USACO22JAN] Multiple Choice Test P

模板題(確信)。

題意:給定 \(N\) 組向量,每組向量有 \(G_i\) 個,每次你需要選擇每一組中的一個向量,問最終這些向量的和到原點的距離的最大值。

解法:先將一組向量畫出來,發現可能成為的點都在凸包上。然後考慮如何合併兩組的答案,發現兩組的答案其實是將其中一組的向量全部平移到另一組向量上,然後再求一次凸包上的點。這就和閔可夫斯基和一樣,於是我們處理出每一組向量的凸包,然後求所有凸包的閔可夫斯基和就行了。

P4557 [JSOI2018] 戰爭

題意:給定兩組點,有 \(Q\) 次詢問,每次問你將第二組點都加上一個向量 \((x_i,y_i)\) 後,平面內是否存在一個點,滿足它既被第一組的點中任意三點構成的三角形覆蓋,又被第二組的點中的任意三點構成的三角形覆蓋。

解法:首先先求出兩組點構成的凸包,接著問題就變成了求兩個凸包是否有交集,這種問題我們使用閔可夫斯基和來求解。題目問的是是否存在一個在凸包 \(B\) 中的點 \(b\) 平移 \(w\) 後與凸包 \(A\) 中的點 \(a\) 相同,即 \(b+w=a\) ,移項得到 \(w=a-b\) 。於是我們將 \(B\) 中的每個點取反就得到了 \(-b\) ,然後求閔可夫斯基和就好了。

最後是判斷一個點是否在凸包內,這裡使用二分。將最後求得的凸包 \(C\) 的右下角的點平移到原點上,然後從原點向詢問的點連一條邊,找到凸包上的一條邊,滿足原點連向它的兩個端點的向量的極角,包含了詢問的點的極角。之後用叉積判斷即可。

相關文章