演算法導論之計算幾何學

2021-09-10 07:37:43 字數 3864 閱讀 8828

所屬專欄: 演算法導論專欄

計算幾何學是電腦科學的乙個分支,專門研究集合問題的解決的演算法。計算幾何學的問題一般輸入關於一組集合物件的描述,如一組點、一組線段;輸出是對問題的回答,如直線是否相交。三維空間和高維空間很難視覺化,這裡計算幾何學主要基於二維平面,輸入物件用一組點來表示,其中每個pi=(xi,yi),xi,yi∈r。

1)線段的性質

兩個不同的點p1=(x1,y1)和p2=(x2,y2)的凸組合是滿足下列條件的任意點p3=(x3,y3):對某個a(0≤a≤1),有x3=ax1+(1-a)x2,y3=ay1+(1-a)y2,即p3=ap1+(1-a)p2。p3是位於穿過p1和p2的直線上、並處於p1和p2之間(包括p1和p2兩點)的任意點,在給定兩個不同的點p1和p2的情況下,線段p1p2是p1和p2的凸組合(convex combination)的集合。p1和p2是線段p1p2的端點,並需要考慮p1和p2之間的順序。

在回答計算集合線段性質上,一般選擇加法、減法、乘法和比較運算,避免使用除法和三角函式,因為這二者計算代價高昂且容易產生捨入誤差降低精度。

叉積:叉積是關於線段演算法的中心,定義為p1xp2,是由點(0,0)、p1、p2、和p1+p2=(x1+x2,y1+y2)所形成的平行四邊形的面積,也等價於乙個矩陣的行列式:

如果p1xp2為正數,則相對於原點(0,0)來說,p1在p2的順時針方向上;如果為負數,則p1在p2的逆時針方向上;如果為0,即在邊界,則兩個向量是共線的,指向同乙個方向或相反的方向。

要確定公共端點p0,有向線段p0p1是否在有向線段p0p2的順時針方向上,可計算叉積:

(p1-p0)x(p2-p0)=(x1-x0)(y2-y0)-(x2-x0)(y1-y0)

如果該積為正,則向線段p0p1在有向線段p0p2的順時針方向上;如果為負,則向線段p0p1在有向線段p0p2的逆時針方向上。

連續線段的轉向判斷:

問題是在點p1處,兩條連續的線段p0p1和p1p2是向左轉還是向右轉,就是確定p0p1p1的角的轉向。應用叉積,檢查有向線段p0p2是在有向線段p0p1的順時針方向還是逆時針方向即可判斷。計算叉積(p2-p0)x(p1-p0),為負,則p0p2在p0p1的逆時針方向,在p1點會左轉;如果為正,則p0p2在p0p1的順時針方向,在p1點會右轉。

兩個線段的相交判斷:

要確定兩個線段是否相交,通過每個線段是否跨越了包含另一條線段的直線。給定乙個線段p1p2,如果點p1位於某一直線的一邊,而點p2位於該直線的另一邊,則稱線段p1p2跨越了該直線。如果p1和p2就落在該直線上的話,就是出現邊界情況。

兩個線段相交,當且僅當下面兩個條件中的乙個成立,或同時成立:

第一:每個線段都跨越包含了另乙個線段的直線;

第二:乙個線段的某一端點位於另一線段上(邊界情況)。

演算法偽碼上主要是兩個過程:第乙個過程是計算每個端點相對於另一條線的方位,就是計算三個點的轉向判斷,得出相對方位d;第二個過程對d非零和零進行判斷。

2)確定任意一對線段是否相交

要確定任意一對線段是否相交,採用掃除技術,演算法執行時間是o(nlgn),其中n是已知的線段數目。掃除技術只確定是否存在相交的線段,並不輸出所有的相交點。掃除演算法的過程,是假設存在一條垂直掃除線,自左向右依次穿過已知的幾何物體,如果從x軸方向來看,就是一組垂直的線沿著時間橫掃。掃除技術有兩點假設:第一假定沒有一條輸入線是垂直的;第二假設沒有三條輸入線相交於同一點。掃除過程中,根據掃除線和線段相交的交點的y座標值進行排序。對乙個一條線段來說,掃除線從線段的左端點開始到右端點離開,過程中y的值隨著x的變化而變化,從而有不同的排序。這個很好理解,兩條線段的y值在前後掃除線的不同時間點具有不同的排序(大小出現顛倒),則說明有相交。

掃除演算法維護兩組資料:第一掃除線狀態,記錄了與掃除線相交的線段之間的關係;第二事件點排程,記錄從左到右的x座標的序列。

掃除線狀態是乙個全序t,用一顆紅黑樹實現,可在t上執行四個操作:

insert(t,s),將線段s插入到t中。

delete(t,s),將線段s從t 中刪除。

above(t,s),返回t中緊靠線段s上面的線段。

below(t,s),返回t中緊靠線段s下面的線段。

演算法的偽碼描述就不具體展開,演算法輸入n個線段組成的集合s,如果s中有任意一對線段相交,則輸出true布林值。演算法整個過程通俗的理解就是:一條垂直的線沿著x軸自左向右掃過去,s集合中的線段在掃除線的每個事件點(x軸上的點)對線段y值進行排序。導論中圖示表示很清晰,也做了證明。

3)尋找凸包

點集q的凸包(convex hull)是乙個最小的凸多邊形p,滿足q中的每個點或者在p的邊界上,或者在p的內部,用ch(q)表示凸包。計算包含n個點的點集的凸包,有兩種都是按照逆時針方向順序輸出凸包的各個頂點,乙個是graham掃瞄法,執行時間o(nlgn);還有乙個是jarvis步進法,執行時間是o(nh)。直觀上說,找出凸包的頂點就可以,兩種演算法都運用了旋轉掃除技術,根據每個頂點對乙個參照頂點的極角大小,依次處理。思路上就是選取參照點,計算凸包中和參照點的關係。

凸包問題和計算幾何中的最遠點對問題也相近,已知平面上的n個點的集合,找出他們中距離最遠的兩個點。還有其他演算法,如增量演算法、分治法、剪枝-搜尋法。

graham掃瞄法:

graham掃瞄法通過設定乙個候選點的堆疊s來解決凸包問題。輸入集合q中的每個點都被壓入棧一次,非凸包ch(q)中頂點的點被彈出堆疊,演算法終止時,堆疊s中僅包含ch(q)中的頂點,其順序為各點在邊界上出現的逆時針方向排列的順序。

具體偽碼和案例及其正確定證明不描述,主要說下演算法過程:首先選擇參照點p0,一般選擇頂點(最下邊或最右邊這種);其次將所有點按照和p0極角大小遞增順序壓入堆疊;接著依次彈出右轉的非凸包頂點,最後剩下就是凸包的頂點。

jarvis步進法:

該方法的思路可以這樣理解:找出q集合中的最低點p0(y值最小),這是凸包的乙個頂點,以該點為基礎放射出一條無限長的線段,從右邊開始沿上掃瞄,直到碰到乙個點(遇到的點都是頂點),直到360度旋轉回p0點。

這個過程中最重要的是,掃瞄過程中界定遇到的點是頂點,理論上,找出具有最小極角的點,如果極角相同再找出距離最遠的點(x軸的距離)。

4)尋找最近點對

在n≥2個點的集合q中尋2找最近點對的問題。最近通常理解為歐幾里得距離,點p1=(x1,y1)和p2=(x2,y2)之間的距離為:

如果集合中兩個點重合,那距離就是0。尋找最近點對問題應用在空中或海洋交通控制系統中,用於發現兩個距離最近的交通工具,以便檢測出可能發生的相撞事故。

一般簡單的做法,就是計算出所有點的兩兩距離,然後得出最近點對,這個演算法是點數n的平方時間效能。如果應用分治演算法,採用遞迴t(n)=2t(n/2)+o(n),演算法執行時間為o(nlgn)。下面描述分治演算法的思路。

分治演算法的每一次遞迴呼叫輸入為子集p⊆q和陣列x和y,每個陣列均包含輸入子集p的所有點。陣列x中點,按x座標單調遞增排序;同樣的,陣列y中的點,按y座標單調遞增排序。遞迴退出在檢查|p|≤3,如果小於等於3個點,那直接就兩兩比較;如果大於3,則接著分治。具體步驟:

第一分解:找出一條垂直線l,將點集p劃分為左右兩個集合pl和pr,需要滿足二者的點數是p的二分之一。自然,陣列x就也劃分兩個陣列xl和xr,陣列y也 劃分為兩個陣列yl和yr。

第二解決:p劃分成pl和pr後,進行兩次遞迴呼叫,一次找出pl的最近點對,返回最近點對距離l,一次找出pr的最近點對,返回最近點對距離r;取min(l,r)返回。

第三合併:最近點對,要麼是某次遞迴呼叫返回的取min(l,r)距離,要麼就是   pl中的乙個點和pr中的乙個點組成點對,演算法中需要確定跨陣列的點對距離和min(l,r)距離關係;如果小於,則點對中的兩個點一定在距離垂直線l的min(l,r)單位內;這樣就建立乙個以垂直線l為中心,寬度為2 min(l,r)的垂直帶形區域內;找出這樣點對,需要對陣列y內不在該區域的點去掉,剩下依舊按照y座標順序排序;對陣列y中在區域內的所有點,找出距離其在min(l,r)單位距離內的點,並記錄下其點對距離;如果存在比min(l,r)更小的,則返回該點及其距離。

演算法的正確性就不多敘述,其實計算幾何需要抽象去理解,好在二維的還是比較好理解。

計算幾何學 3

點的內包 判斷點是否在多邊形內。輸入 乙個多邊形點的序列 問題數各個問題的點的資訊 輸出 2代表在圈內 1代表在圈上 0代表在圈外 只要檢查一p為端點且平行於x的射線與多邊形g的邊的相交次數,我們就能判斷給定的點p是否內包與多邊形g。對於構成多邊形各邊的線段設如果a和b外積大小為0且內積小於等於0,...

計算幾何學簡單的模板

一些定義 include include include include include using namespace std define maxn 1200 define eps 1e 8 struct point po maxn struct line typedef point vecto...

我的計算幾何學題目分類

uva11646 sdutoj2603 poj1269 poj1410 poj1328 貪心 uva12304 三角 圓基本關係 poj1556 線段相交 最短路 poj2966 凸包 最短路 poj2031 最小生成樹 poj2318 poj2398 二分 hdu1086 基礎 poj2007 極...