平面最近點對問題詳解

2021-08-17 11:21:48 字數 2633 閱讀 1215

演算法:   

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個點兩兩進行組...