前言
畫乃我思所欲,非我見所得。
幾何算法常常出現在計算機圖形學,大規模集成電路設計等方面,常常需要分析平面內點、線段、直線的關係,而其算法呢大多用到了歸納,分治等算法的思想。
幾何算法舉例
1.判斷點是否在多邊形內部
判斷p是否在多邊形內部?
從p連一條到多邊形外部的點的直線
看與所有多邊形的邊相交幾次
若爲奇數
則在內部
如何找外部的點?
找一個點x值比多邊形的所有點x值都大
2.構造多邊形
平面內給n個點,怎麼構造一個多邊形
(1)
造一個圓包含多邊形的所有點
然後從圓心繞一圈按順序連接所有點
這就是個多邊形
(2)
選擇多邊形x,y都最小的那個點
然後整個圖就在1,2象限了
這樣從角度的小到大連接所有點,就是多邊形
3.凸包算法
尋找n個點的凸包
(1)
歸納
假設我們可以找到n-1個點的凸包
加入第n點
要麼在凸包中,不用操作,
檢測是否在凸包中
前面判斷點是否在多邊形中
O(n)
要麼不在凸包中
要拓展凸包
刪去原來在邊上,現在在裏面的點
遍歷
支撐線:vn 與 vi vj 的直線分別於x軸角度是最大和最小
然後刪點
T(n) = T(n - 1) + O(n)
O(n*n)
(2)
優化
禮物包裹算法
從一個點一個一個往過包
就像紙包紅薯
先折一次,再折
就是第一個點,第二個點
第三個點
1,2向量與2,3向量角度最小
就是凸包
每個點需要與所有點計算角度
O(n * n)
(3)
優化
Graham掃描算法
選最右下角的點a
排序-每個點與a直線與x軸角度大小
從一個點往下找
排序後1,2點入棧
新加入3的與棧頂兩元素比較
若向量旋轉方向逆
就入棧
若順
就棧頂元素出棧
循環
3 與棧頂兩元素再比
這樣排序O(nlogn)
每個點回溯
總回溯不會超過O(n)
總O(nlogn)
4.找最近點對
給出平面內的n個點,找出距離最小的點
(1)
暴力搜索
n個點兩兩計算距離
N*(n-1)/2
(2)
分治
歸納
將原n個點找到x座標最中間的一個,以這個點的豎線分兩堆
假設我們已知n/2個點堆中的最小距離
推廣的n
左邊最小值d1, 右邊最小值d2
D= min(d1, d2)
計算豎線兩邊+-d範圍內的點兩兩最小值
因爲外面的不可能有跨界還小於d的
最壞情況
n個點都在中間區域內
。。。
Tn = 2T(n/2) + O(n^2)
還O(n^2)
優化
其實每個點找對面界中的點時
只用找[y - d, y + d]的點
有對面界的最小距離爲d
將中間區域的點按y排序(O(nlogn))
每個點只會與對面界的最多6個點檢查一遍
所以檢查時間爲常數O(n)
Tn = 2T(n/2) + O(nlogn)
O(n(logn)^2)
再優化
增強歸納
我們不但知道n/2堆的最小距離,我們還知道其中點y值的排序
這樣求中間的時候就可以直接合並
類似於歸併排序
Tn = 2T(n/2) + O(n)
O(nlogn)
5.求水平線與豎直線的交點
平面內有n條水平線,m條豎直線,求交點
(1)
暴力
兩兩求O(mn)
(2)
將所有線端點x值排序
O((m+n)log(m+n))
掃描線
設置一條豎線從平面左邊到平面右邊
(1)是左端點,就入隊,表示這條線有產生交點的希望
(2)是右端點,就這條直線出隊
(3)是豎線,就與隊列中的水平線比較,是否產生交點
掃描
檢查M+n個點
豎直線的話要檢查所有水平點
最壞(m+n)n
優化
維護有希望的水平線以y值排序的堆
這樣判斷是否相交就用豎直線的兩個端點二分查找
O(m+n)logn
總結
幾何算法的問題我們常常會說這肉眼看看不就出來了嗎,但幾何算法就是這樣,它是讓計算機解的方法。設計幾何算法時,要注意不要被腦子裏的慣式圖形所誤導,要考慮特殊情況。