問題
給定平面上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個點所構成的乙個凸包上 證明略 那麼可以...