演算法:
0:把所有的點按照橫座標排序
1:用一條豎直的線l將所有的點分成兩等份
2:遞迴算出左半部分的最近兩點距離d1,右半部分的最近兩點距離d2,取d=min(d1,d2)
3:算出「乙個在左半部分,另乙個在右半部分」這樣的點對的最短距離d3。
4:結果=min(d1,d2,d3)
關鍵就是這第3步。貌似這需要n^2的時間,把左邊每個點和右邊每個點都對比一下。其實不然。秘密就在這裡。 首先,兩邊的點,與分割線l的距離超過d的,都可以扔掉了。 其次,即使兩個點p1,p2(不妨令p1在左邊,p2在右邊)與分割線l的距離(水平距離)都小於d,如果它們的縱座標之差大於d,也沒戲。 就是這兩點使得搜尋範圍大大減小: 對於左半部分的,與l的距離在d之內的,每個p1來說:右半部分內,符合以上兩個條件的點p2最多只有6個! 原因就是: d是兩個半平面各自內,任意兩點的最小距離,因此在同乙個半平面內,任何兩點距離都不可能超過d。 我們又要求p1和p2的水平距離不能超過d,垂直距離也不能超過d,在這個d*2d的小方塊內,最多只能放下6個距離不小於d的點。 因此,第3步總的比較距離的次數不超過n*6。
第3步的具體做法是:
3.1 刪除所有到l的距離大於d的點。 o(n)
3.2 把右半平面的點按照縱座標y排序。 o(nlogn)
3.3 對於左半平面內的每個點p1,找出右半平面內縱座標與p1的縱座標的差在d以內的點p2,計算距離取最小值,算出d3。 o(n*6) = o(n) 因為3.2的排序需要o(nlogn), 所以整個演算法的複雜度就是o(n((logn)^2))。
改進: 我們對3.2這個排序的o(nlogn)不太滿意。 既然整個演算法是遞迴的,我們可以利用第2步的子遞迴中已經排好序的序列,在第3.2部歸併這兩個子列,這樣3.2的複雜度變成了o(n)。 這樣,整個演算法就是o(nlogn)的。
在二維平面上的n個點中,如何快速的找出最近的一對點,就是最近點對問題。
一種簡單的想法是暴力列舉每兩個點,記錄最小距離,顯然,時間複雜度為o(n^2)。
在這裡介紹一種時間複雜度為o(nlognlogn)的演算法。其實,這裡用到了分治的思想。將所給平面上n個點的集合s分成兩個子集s1和s2,每個子集中約有n/2個點。然後在每個子集中遞迴地求最接近的點對。在這裡,乙個關鍵的問題是如何實現分治法中的合併步驟,即由s1和s2的最接近點對,如何求得原集合s中的最接近點對。如果這兩個點分別在s1和s2中,問題就變得複雜了。
為了使問題變得簡單,首先考慮一維的情形。此時,s中的n個點退化為x軸上的n個實數x1,x2,...,xn。最接近點對即為這n個實數中相差最小的兩個實數。顯然可以先將點排好序,然後線性掃瞄就可以了。但我們為了便於推廣到二維的情形,嘗試用分治法解決這個問題。
假設我們用m點將s分為s1和s2兩個集合,這樣一來,對於所有的p(s1中的點)和q(s2中的點),有p
遞迴地在s1和s2上找出其最接近點對和,並設
d = min
由此易知,s中最接近點對或者是,或者是,或者是某個,如下圖所示。
此時,一維情形下的最近點對時間複雜度為o(nlogn)。
在二維情形下,類似的,利用分治法,但是難點在於如何實現線性的合併?
由上圖可見,形成的寬為2d的帶狀區間,最多可能有n個點,合併時間最壞情況下為n^2,。但是,p1和p2中的點具有以下稀疏的性質,對於p1中的任意一點,p2中的點必定落在乙個d x 2d的矩形中,且最多隻需檢查六個點(鴿巢原理)。
這樣,先將帶狀區間的點按y座標排序,然後線性掃瞄,這樣合併的時間複雜度為o(nlogn),幾乎為線性了。
/**最近點對問題,時間複雜度為o(n*logn*logn)
*/#include
#include
#include
#include
#include
using
namespace
std;
const
double
inf = 1e20;
const
intn = 100005;
struct
point
point[n];
intn;
inttmpt[n];
bool
cmpxy(
const
point& a,
const
point& b)
bool
cmpy(
const
int& a,
const
int& b)
double
min(
double
a, double
b)
double
dis(
inti,
intj)
double
closest_pair(
intleft,
intright)
sort(tmpt,tmpt+k,cmpy);
//線性掃瞄
for(i = 0; i
} return
d;
} int
main()
return
0;
}
平面最近點對問題詳解
演算法 0 把所有的點按照橫座標排序 1 用一條豎直的線l將所有的點分成兩等份 2 遞迴算出左半部分的最近兩點距離d1,右半部分的最近兩點距離d2,取d min d1,d2 3 算出 乙個在左半部分,另乙個在右半部分 這樣的點對的最短距離d3。4 結果 min d1,d2,d3 關鍵就是這第3步。貌...
平面最近點對問題
平面最近點對問題正如其名,給定平面上的 n 個點,找出其中的一對點,使得這對點的距離在所有點對中最小。首先顯而易見地我們可以得到這個問題的 o n 2 演算法,列舉所有點對即可。但是很顯然我們可以注意到,這裡面有很多點對顯然不是最優的,那麼我們可以想到一種剪枝方法,就是將只對x座標差值小於當前已知最...
平面最近點對問題求解
問題描述 最近點對問題是指求解平面點集n個點中距離最近的兩個點間的問題。為簡單起見,在二維座標平面來考慮該問題。如果說討論的點以標準二維座標給出,則有點 本章主要通過兩種方法來求解 蠻力法分治法 顧名思義,蠻力法指的就是通過遍歷所有解之後通過對比求出最近點對問題。基本思路 對平面中的n個點兩兩進行組...