培訓- 8 計算幾何学
計算幾何学
c2251393
November 30, 2013
1 計算幾何
計算幾何是一個非常大的分類,最出名的運用就是現在看到的很多 3D 圖形製 作、遊戲引擎等。在高中的算法競賽也是一種題型(隨然近年來越來越少見,尤其是 IOI)。
以下我們通常只討論二維平面的計算幾何。
1.1 浮點數誤差 (EPS)
在平面幾何的運算中,並沒有什麼理由限制座標必需為整數,因此常常牽涉到浮 點數的運算。
浮點數一般使用 double 或 long double 型別來儲存,其精確度有一定的上限 值。因此不可避免地,在浮點數的四則運算當中,會產生一些誤差。例如電腦可能 計算 1.0 + 1.0 = 1.99999999999999999,而這時電腦會認為1.0 + 1.0̸= 2.0,導致程 式出現問題。
因此在比對兩數值是否相等時,應容許一些很小的誤差。例如令 EP S = 10−10, 而兩數差的絕對值 ≤EP S 時,判斷兩數相等,如此即可解決大部份誤差問題。
1.2 內積
向量⃗a 與⃗b的內積寫作⃗a·⃗b。即
⃗a·⃗b =xaxb+yayb =|⃗a||⃗b|cosθ θ 是這兩個向量的夾角。
I
1.3 平面上的外積 計算幾何学
1.3 平面上的外積
向量⃗a 與⃗b的外積寫作⃗a×⃗b。即
⃗a×⃗b=xayb−yaxb =|⃗a||⃗b|sinθ
這個值的絕對值相當於這兩個向量圍出來的平行四邊形面積,另外若⃗b在⃗a 的逆 時針方向(即左邊),那麼⃗a×⃗b >0。外積的正負號,可以用來判斷兩向量之類的順 逆時針關係。
1.4 判斷線段相交
給定兩線段 P1P2, Q1Q2 四個端點 P1, P2, Q1, Q2 的座標,判斷這兩線段是否相交。
方法有兩個,
1. 可直接求出兩直線方程式,找出交點,再判斷是否在兩線段範圍內。(誤差大,
麻煩)
2. 跨立檢驗:若 P1, P2 在 Q1Q2 異側,且 Q1, Q2 在 P1P2 異側,則此兩線段相 交。即判斷下列兩式是否皆成立:
(−−→
P1P2×−−−→
P1Q1)(−−→
P1P2×−−−→
P1Q2)<0 (−−−→
Q1Q2×−−−→
Q1P1)(−−−→
Q1Q2×−−−→
Q1P2)<0
1.5 多邊形面積計算
給定一無邊相交的多邊形 P1, P2, P3, , , Pn,可計算此多邊形面積:(為了方便,令 Pn+1 =P1)
1 2|
∑n
1
−−→OPk×−−−−→
OPk+1|
將四邊形分割成許多三角形 (面積可為負) 即可導出此式。時間複雜度顯然為 O(n)。
1.6 點在多邊形內部
給定一個點 A 和n 多邊形P1, P2, , , Pn,判斷 A 是否在多邊形內
II
1.7 凸包 計算幾何学
由 A 點往外作射線,若此射線交多邊形的邊奇數次,則 A 在多邊形內;若交偶數 次,則 A 在多邊形外 (需先判掉 A 在頂點或邊上的狀況)。射線方向儘量隨機,以 避免剛好交到頂點等例外狀況。
若該多邊形是凸多邊形且 A 在多邊形內,而多邊形點的順序正好是由 A 為參考 點的極角排序。因此,所有的−−→
APk×−−−−→
APk+1 皆同號。這些外積中,若有異號代表 A 在凸多邊形外;若有一個0,代表 A 在某一條邊上;若有兩個0,代表 A 在某一頂 點上。
1.7 凸包
對於一個點集,找出其中一些點,使得點集中的所有點,都在由這些選中的點所 圍成的凸多邊形之內或邊界上。
算法 將凸包分成上下兩部份分開求。
首先將所有點依 x 座標排序,x 座標相同時照 y 座標排序。排序完後的第一個點
(最左,最下) 和最後一個點 (最右,最上) 都必在凸包上。先從第一個點(最左,最
下) 開始求上半部的凸包。開一個stack 存放屬於上半部凸包的點。首先把排序前 2 個點丟進去。隨時考慮 stack 中倒數 2 個點 A, B(B 為最後一個點) 以及排序中 的下一個點C。如果 A−B−C為一逆時針轉動,則表明 B 不在凸包上,故把B 刪 掉。若stack 剩不到 2 個點或A−B−C 為一順時針轉動,則將C 放進 stack中,
並從排序中移除。一直重覆此動作,直到排序被清空,此時 stack中的點就是上半 部的凸包。以相同的方式從最後一個點開始,求出下半部的凸包,再合併後可得到 完整的凸包。
時間複雜度為 O(n)(若所有點已經排序好了)。
1.8 Exercises!!!
1. Ch特別篇 -6. 我不是妹控(STEP5 0052)
給你 N 個紅點跟 M 個黑點,問最少有幾個黑點在可由紅點所組成的多邊形 外。(N, M ≤1000)
2. 古代巨塔之謎 (NPSC 2012 高中組決賽)
平面上 N 個點,輸出能包住這些點的最小矩形面積。
III
2.解題技巧 1 計算幾何学
2 解題技巧 1
以下將介紹一些解題時好用的技巧,為了好理解及清楚說明在實務上的做法,每 個技巧將會用一兩個例題來講解。
2.1 Meet in the middle
HOJ 132 給你最多 30 個物品,每個物品有價值 c(−109 ≤ c ≤ 109),問是否存 在一個集合S 滿足 ∑
i∈Sci = 0。
很簡單的想法是 O(2n) 爆搜,然後亂剪枝。但這實在不是很營養的辦法,那所以 有沒有複雜度合理一點的算法呢?
不難發現任何一個集合都是從前 15 個物品中找一些、後 15 個找一些,然後合 併出來。所以我們可以把前15 個跟後 15 個的所有子集合 (215 + 215) 算出來,然 後對於前半的每種子集合,搜尋看說後半的每種子集合中是否有集合跟他加起來是 0的,這明顯把後半每個子集合的權重都丟到平衡樹裡,就可以 O(lgn) 的時間完成 搜尋。
這樣子的時間複雜度是 O(2n2 ×2 + 2n2 ×lg2n2),這最大也就500000左右而已,相 當理性的計算量。
Exercises!!
1. Balanced Cow Subset (USACO open 2012 gold)
給你 n(≤ 20) 隻乳牛,每隻乳牛有他的產乳量 mi,你現在要把這些乳牛分成 黑牛、棕牛和白牛,滿足黑牛的總產乳量= 棕牛的產乳量,問有幾種" 把牛分 到白牛的方法"。
2.2 啟發式合併
HOJ 191 給你一顆有根樹(100000個節點),某些葉子上有重量為 wi 的寶藏,對 於每個非葉節點輸出它的有寶藏的葉子小孩們重量差距最小是多少。
第一眼應該會想到一個解法,對於每個節點把她所有寶藏葉子小孩排序好,然後 掃過去計算答案。但這複雜度是很不妙的O(N2)。
IV
2.2 啟發式合併 計算幾何学
那這時應該可以想到了一個優化,對於一個節點,你要計算的其實只是他各個寶 藏葉子小孩對其他顆子樹的最小差距,也就是找他在某顆子樹的lower bound 或 是upper bound 跟他的差距取min。
不意外的話你現在有一個做法是這樣:
對於一個點依序把每顆子樹的所有寶藏小孩加進自己的集合,但加進去之前不忘更 新這個點的答案。
為了方便取 upper bound 跟lower bound 所以會用平衡樹當作自己的" 集合"
的資料結構,所以複雜度會變成O(N2lgN),更不妙了。
那到底怎麼辦 OAOOO。
走投無路的你開始胡思亂想了。如果我每次合併平衡樹的時候是由小顆的一個一 個點加進大顆的樹,那複雜度應該會好一點吧....
到底會好到多少呢? 你發現你的複雜度其實就是"N× 插入的次數 × 插入一次的 時間",所以每個寶藏小孩插入別人的次數是多少呢? 因為每次都是由小的插到大 的,所以假如這次某隻寶藏小孩所在平衡樹的大小是 x,那插入後所在的平衡數大
小至少是2x,而且如果這隻寶藏小孩所在的平衡數大小就是 N 的話,那他在也不
會去插入任何人了(因為他已經在最大的平衡樹裡了),所以他只會待過lgN 顆平衡 樹。所以總複雜度就變成了O(N lg2N),真是神奇。
Exercises!!
1. Tree rotations (POI XVIII)
給你一顆二元樹,滿足每個非葉節點都有兩個小孩,每個葉子都有一個 1 ∼n 的數字且互不相同,讓 S 為所有葉子以前序表示法排列而成的序列,你現在 可以對這棵二元樹任一個非葉節點對調他的左子樹跟右子樹,問你最小要調換 幾次才能使新的 S 的逆序數對數最少。
V