凸包問題的五種解法

2021-07-11 15:53:23 字數 3959 閱讀 9359

首先,什麼是凸包?

假設平面上有p0~p12共13個點,過某些點作乙個多邊形,使這個多邊形能把所有點都「包」起來。當這個多邊形是凸多邊形的時候,我們就叫它「凸包」。如下圖:

然後,什麼是凸包問題?

我們把這些點放在二維座標系裡面,那麼每個點都能用 (x,y) 來表示。

現給出點的數目13,和各個點的座標。求構成凸包的點?

時間複雜度:o(n³)。

思路:兩點確定一條直線,如果剩餘的其它點都在這條直線的同一側,則這兩個點是凸包上的點,否則就不是。

步驟:將點集裡面的所有點兩兩配對,組成 n(n-1)/2 條直線。

對於每條直線,再檢查剩餘的 (n-2) 個點是否在直線的同一側。

如何判斷乙個點 p3 是在直線 p1p2 的左邊還是右邊呢?(座標:p1(x1,y1),p2(x2,y2),p3(x3,y3))

當上式結果為正時,p3在直線 p1p2 的左側;當結果為負時,p3在直線 p1p2 的右邊。

時間複雜度:o(n㏒n)。

思路:應用分治法思想,把乙個大問題分成幾個結構相同的子問題,把子問題再分成幾個更小的子問題……。然後我們就能用遞迴的方法,分別求這些子問題的解。最後把每個子問題的解「組裝」成原來大問題的解。

步驟:把所有的點都放在二維座標系裡面。那麼橫座標最小和最大的兩個點 p1 和 pn 一定是凸包上的點(為什麼呢?用反證法很容易證明,這裡不詳講)。直線 p1pn 把點集分成了兩部分,即 x 軸上面和下面兩部分,分別叫做上包和下包。

對上包:求距離直線 p1pn 最遠的點,即下圖中的點 pmax 。

作直線 p1pmax 、pnpmax,把直線 p1pmax 左側的點當成是上包,把直線 pnpmax 右側的點也當成是上包。

重複步驟 2、3。

對下包也作類似操作。

然而怎麼求距離某直線最遠的點呢?我們還是用到解一中的公式:

設有乙個點 p3 和直線 p1p2 。(座標:p1(x1,y1),p2(x2,y2),p3(x3,y3))

對上式的結果取絕對值,絕對值越大,則距離直線越遠。

注意:在步驟一,如果橫座標最小的點不止乙個,那麼這幾個點都是凸包上的點,此時上包和下包的劃分就有點不同了,需要注意。

時間複雜度:o(nh)。(其中 n 是點的總個數,h 是凸包上的點的個數)

思路:

注意:找第二個點 p1 時,因為已經找到的只有 p0 乙個點,所以向量只能和水平線作夾角 α,當 α 最小時求得第二個點。

時間複雜度:o(n㏒n)

思路:graham掃瞄的思想和jarris步進法類似,也是先找到凸包上的乙個點,然後從那個點開始按逆時針方向逐個找凸包上的點,但它不是利用夾角。

步驟:把所有點放在二維座標系中,則縱座標最小的點一定是凸包上的點,如圖中的p0。

把所有點的座標平移一下,使 p0 作為原點,如上圖。

計算各個點相對於 p0 的幅角 α ,按從小到大的順序對各個點排序。當 α 相同時,距離 p0 比較近的排在前面。例如上圖得到的結果為 p1,p2,p3,p4,p5,p6,p7,p8。我們由幾何知識可以知道,結果中第乙個點 p1 和最後乙個點 p8 一定是凸包上的點。

(以上是準備步驟,以下開始求凸包)

以上,我們已經知道了凸包上的第乙個點 p0 和第二個點 p1,我們把它們放在棧裡面。現在從步驟3求得的那個結果裡,把 p1 後面的那個點拿出來做當前點,即 p2 。接下來開始找第三個點:

連線p0和棧頂的那個點,得到直線 l 。看當前點是在直線 l 的右邊還是左邊。如果在直線的右邊就執行步驟5;如果在直線上,或者在直線的左邊就執行步驟6。

如果在右邊,則棧頂的那個元素不是凸包上的點,把棧頂元素出棧。執行步驟4。

當前點是凸包上的點,把它壓入棧,執行步驟7。

檢查當前的點 p2 是不是步驟3那個結果的最後乙個元素。是最後乙個元素的話就結束。如果不是的話就把 p2 後面那個點做當前點,返回步驟4。

最後,棧中的元素就是凸包上的點了。

以下為用graham掃瞄法動態求解的過程:

說真的,這個演算法我也還沒有看清。網上的資料也少的可憐,我暫且把網上的解釋截個圖在這裡,往後搞懂以後再回來補上。

或者有人看懂了的,希望不吝指教,不甚感激!

以上討論的只是二維的凸包,如果延生為三維、多維的凸包問題呢?如何求解?

不過首先,二維凸包可以用來解決圍欄問題、城市規劃問題、聚類分析等等。但是三維、多維的凸包可能的使用範疇有哪些?

附:尋找凸包的graham演算法

#include

#include

using namespace std;

/*pointset:輸入的點集

ch:輸出的凸包上的點集,按照逆時針方向排列

n:pointset中的點的數目

len:輸出的凸包上的點的個數

*/struct point

;//小於0,說明向量p0p1的極角大於p0p2的極角

float multiply(point p1,point p2,point p0)

float dis(point p1,point p2)

void graham_scan(point pointset,point ch,int n,int &len)

len=top+1;

}const int maxn=1010;

point pointset[maxn];

point ch[maxn];

int n;

int len;

int main()

if(r > rmax)

}if(rmax <= 0)

}return;

}else

getresult(resultpack,x1,y1,pack[tmax][0],pack[tmax][1]);

getresult(resultpack,pack[tmax][0],pack[tmax][1],x2,y2);

}void main()

else

if(x3 > x2)

}g_result[1][0] = x1;

g_result[1][1] = y1;

g_result[2][0] = x2;

g_result[2][1] = y2;

g_result[0][0] += 2;

getresult(point, x1, y1, x2, y2);

getresult(point, x2, y2, x1, y1);

printf("\n\n構成凸包的點有:\n");

for(i=1;i<=g_result[0][0];i++)

printf("(%d,%d)\n",g_result[i][0],g_result[i][1]);

system("pause");

}

凸包問題的五種解法

首先,什麼是凸包?假設平面上有p0 p12共13個點,過某些點作乙個多邊形,使這個多邊形能把所有點都 包 起來。當這個多邊形是凸多邊形的時候,我們就叫它 凸包 如下圖 然後,什麼是凸包問題?我們把這些點放在二維座標系裡面,那麼每個點都能用 x,y 來表示。現給出點的數目13,和各個點的座標。求構成凸...

凸包問題的五種解法

前言 首先,什麼是凸包?說凸包首先要說凸性的定義,簡單點說就是平面鄰域中任意兩點所在的線段上的點都在該鄰域中,則該鄰域具有凸性。簡單推敲一下,就可以發現如果鄰域中存在一階導數不連續的點一定無法被某點集線性表示出來。再往下的內容屬於數學分析了,對我們的演算法設計幫助不大,暫時先不管。假設平面上有p0 ...

凸包問題的五種解法

首先,什麼是凸包?假設平面上有p0 p12共13個點,過某些點作乙個多邊形,使這個多邊形能把所有點都 包 起來。當這個多邊形是凸多邊形的時候,我們就叫它 凸包 如下圖 然後,什麼是凸包問題?我們把這些點放在二維座標系裡面,那麼每個點都能用 x,y 來表示。現給出點的數目13,和各個點的座標。求構成凸...