http://www.csie.ntnu.edu.tw/~u91029/VoronoiDiagram.html
Voronoi Diagram
程度★ 難度★★
Voronoi Diagram
平面上散布許多點。平面上每一處,各自歸類於最近的點;自然而然的,形成了分界線,是中垂線。 Voronoi Diagram 是分界線組成的集合。 Voronoi 是發明者的姓氏。
換個角度看。鄰近的點的中垂線,形成 Voronoi Diagram 。

Voronoi Diagram 隱含著鄰近的資訊,所以「最靠近」、「距離最短」之類的問題,多半可以透過 Voronoi Diagram 解決。

Voronoi Diagram 是大自然的圖案,諸如長頸鹿的斑紋、蜻蜓的翅膀、葉片的細胞壁。應用相當廣泛。


Perpendicular Bisector
「中垂線」,中學數學,不再贅述。

- typedef complex<double> Point;
- typedef pair<Point,Point> Line;
- #define x real()
- #define y imag()
- Line pb(Point& a, Point& b)
- {
- // ab中點。
- Point c = (a + b) / 2.0;
- // ab向量,顛倒、變號,得到法向量。
- Point s = b - a;
- swap(s.x, s.y);
- s.x *= -1;
- // 中垂線。兩點得一線。
- return make_pair(c, c + s);
- }
三角形的三中垂線,交於一點,是外接圓圓心,稱作外心。中垂線有等距、平分的感覺,圓有等距、歸心的感覺,兩者關係匪淺。

由此可知, Voronoi Diagram 一個點至少連著三條邊。
Voronoi Diagram 點和邊的數量

Voronoi Diagram 看上去就像個平面圖。延伸至無限遠的邊,通通接往一個點, Voronoi Diagram 就變成平面圖。
運用平面圖歐拉公式 v-e+f=2 ,輔以「一個點至少連著三條邊」的限制,可以推理出 Voronoi Diagram 最多有 2N-5 個點、 3N-6 條邊,都是 O(N) 。
延伸閱讀:勢力消長
每個點設定不同的強度,兩點之間依照強度比例劃定界線。理論上可以生成所有平面圖?

延伸閱讀:歸類於第 k 近的點
平面上每一處,各自歸類於第 k 近的點,就形成了 Order k Voronoi Diagram 。至於這有什麼用途,我也不知道。
為了辨識每塊區域歸類於哪一點,我們將每個點標上不同顏色,讓區域的顏色對應點的顏色。
上方圖片以 HTML5 Canvas 繪製而成,演算法是窮舉法。有興趣的讀者請自行檢視網頁原始碼。
延伸閱讀:歸類於最遠的點
既有最近,亦有最遠。平面上每一處,各自歸類於最遠的點,就形成了 Farthest Point Voronoi Diagram 。
換個角度看。相離最遠的點,自然而然都在凸包上,證明請參考「 Farthest Pair 」。相離最遠的點的中垂線,形成 Farthest Point Voronoi Diagram 。

延伸閱讀:點改成其他東西
我們可以把一個點改成一個圓、一條線段、一群點、一個多邊形等等圖形,得到各式各樣的 Voronoi Diagram 。
這些都是進階課題,有興趣的讀者請自行尋找資料。
Voronoi Diagram:
Half-plane Intersection
程度★ 難度★
枚舉每一點,求得該點的區域:與其他點形成的 N-1 條中垂線,求半平面交集。時間複雜度為 O(N * NlogN) 。
UVa 12109
Voronoi Diagram:
Incremental Method
程度★ 難度★★
http://nodename.com/wpEmbeds/VoronoiToy/bin/PlanePointsApp.swf
online 演算法,一次加一點。先找到當前輸入點相距最近的點,然後以中垂線繞行一圈求得當前輸入點的區域。

Voronoi Diagram 的點數和邊數都是 O(N) 。就算是窮舉路線轉折點所在的邊,整體時間複雜度仍是 O(N^2) 。
附帶一提,當給定的點都在凸包上時,使用 Randomized Incremental Method 可達 O(N) 。
http://www.cs.dartmouth.edu/reports/TR90-147.pdf
UVa 12311
Voronoi Diagram:
Divide and Conquer
程度★★ 難度★★
http://students.info.uaic.ro/~emilian.necula/vor2.pdf
所有點分成左右兩側,分別求出 Voronoi Diagram ,然後合而為一。
從左右 Convex Hull 的外公切線的中垂線開始行進,一旦撞到左右 Voronoi Diagram ,就改變行進方向。
至於要如何清除多餘的 Voronoi Diagram ,我也不知道。

時間複雜度是 O(NlogN) ,但是步驟繁雜,實際運行速度極慢。讀者只需知道 Voronoi Diagram 存在這麼一個解題策略就行了,不需浪費時間鑽研細節。
Voronoi Diagram:
Fortune's Algorithm
程度★★ 難度★★★
http://www.cs.hmc.edu/~mbrubeck/voronoi.html
平移的掃描線。時間複雜度是 O(NlogN) ,實務上效率極佳。