尋找最遠點對

2021-07-29 16:36:17 字數 2120 閱讀 5012

問題

給定平面上n個點的座標,找出距離最遠的兩個點。

分析類似於「最近點對問題」,這個問題也可以用列舉的方法求解,時間複雜度o(n^2)。

「尋找最近點對」是用到分治策略降低複雜度,而「尋找最遠點對」可利用幾何性質。注意到:對於平面上有n個點,這一對最遠點必然存在於這n個點所構成的乙個凸包上(證明略),那麼可以排除大量點,如下圖所示:

在得到凸包以後,可以只在頂點上面找最遠點了。同樣,如果不o(n^2)兩兩枚舉,可以想象有兩條平行線, 「卡」住這個凸包,然後卡緊的情況下旋轉一圈,肯定就能找到凸包直徑,也就找到了最遠的點對。或許這就是為啥叫「旋轉卡殼法」。

總結起來,問題解決步驟為:

1、用graham's scanning求凸包

2、用rotating calipers求凸包直徑,也就找到了最遠點對。

該演算法的平均複雜度為o(nlogn) 。最壞的情況下,如果這n個點本身就構成了乙個凸包,時間複雜度為o(n^2)。

旋轉卡殼可以用於求凸包的直徑、寬度,兩個不相交凸包間的最大距離和最小距離等。雖然演算法的思想不難理解,但是實現起來真的很容易讓人「卡殼」。

逆向思考,如果qa,qb是凸包上最遠兩點,必然可以分別過qa,qb畫出一對平行線。通過旋轉這對平行線,我們可以讓它和凸包上的一條邊重合,如圖中藍色直線,可以注意到,qa是凸包上離p和qb所在直線最遠的點。於是我們的思路就是列舉凸包上的所有邊,對每一條邊找出凸包上離該邊最遠的頂點,計算這個頂點到該邊兩個端點的距離,並記錄最大的值。直觀上這是乙個o(n2)的演算法,和直接列舉任意兩個頂點一樣了。但是注意到當我們逆時針列舉邊的時候,最遠點的變化也是逆時針的,這樣就可以不用從頭計算最遠點,而可以緊接著上一次的最遠點繼續計算,於是我們得到了o(n)的演算法。

[cpp]view plain

copy

// 求最遠點對

#include

#include

using

namespace

std;  

struct

point  

p[50005];  

inttop , stack[50005];    

// 凸包的點存在於stack中

inline

double

dis(

const

point &a , 

const

point &b)  

inline

intmax(

inta , 

intb)  

inline

intxmult(

const

point &p1 , 

const

point &p2 , 

const

point &p0)  

intcmp(

const

void

* a , 

const

void

* b) 

//逆時針排序 返回正數要交換

void

graham(

intn) 

//形成凸包

inttemp = top;  

for(i = n-2 ; i >= 0 ; --i)  

}  introtating_calipers()  

//卡殼

return

ans;  

}  int

main(

void

)    

swap(p[0] , p[leftdown]);  

graham(n);  

printf("%d\n"

,rotating_calipers());    

}  return

0;  

}  

尋找最遠點對

問題 給定平面上n個點的座標,找出距離最遠的兩個點。分析類似於 最近點對問題 這個問題也可以用列舉的方法求解,時間複雜度o n 2 尋找最近點對 是用到分治策略降低複雜度,而 尋找最遠點對 可利用幾何性質。注意到 對於平面上有n個點,這一對最遠點必然存在於這n個點所構成的乙個凸包上 證明略 那麼可以...

尋找最遠點對

在乙個實際專案中遇到 尋找最遠點對 問題,猛然想起 程式設計之美 擴充套件問題提到過,開心地翻出來看,卻發現 最近點對 的思路套 最遠 貌似不合適。然後開始查文獻 做實驗,改進演算法,困擾半天也發現了不少實際問題,寫出來大家參考。最後,演算法用到系統中,雖然沒有大幅提高遺傳演算法效率,但是系統評價功...

尋找最遠點對

問題 給定平面上n個點的座標,找出距離最遠的兩個點。分析類似於 最近點對問題 這個問題也可以用列舉的方法求解,時間複雜度o n 2 尋找最近點對 是用到分治策略降低複雜度,而 尋找最遠點對 可利用幾何性質。注意到 對於平面上有n個點,這一對最遠點必然存在於這n個點所構成的乙個凸包上 證明略 那麼可以...