平面最接近點對問題 分治

2021-08-30 06:28:10 字數 1692 閱讀 3021

主要思想就是分治。先把n個點按x座標排序,然後求左邊n/2個和右邊n/2個的最近距離,最後合併。合併要重點說一下,比較麻煩。

首先,假設點是n個,編號為1到n。我們要分治求,則找乙個中間的編號mid,先求出1到mid點的最近距離設為d1,還有mid+1到n的最近距離設為d2。這裡的點需要按x座標的順序排好,並且假設這些點中,沒有2點在同乙個位置。(若有,則直接最小距離為0了)。

然後,令d為d1, d2中較小的那個點。如果說最近點對中的兩點都在1-mid集合中,或者mid+1到n集合中,則d就是最小距離了。但是還有可能的是最近點對中的兩點分屬這兩個集合,所以我們必須先檢測一下這種情況是否會存在,若存在,則把這個最近點對的距離記錄下來,去更新d。這樣我們就可以得道最小的距離d了。

關鍵是要去檢測最近點對,理論上每個點都要和對面集合的點匹配一次,那效率還是不能滿足我們的要求。所以這裡要優化。怎麼優化呢?考慮一下,假如以我們所選的分割點mid為界,如果某一點的橫座標到點mid的橫座標的絕對值超過d1並且超過d2,那麼這個點到mid點的距離必然超過d1和d2中的小者,所以這個點到對方集合的任意點的距離必然不是所有點中最小的。

所以我們先把在mid為界左右乙個範圍內的點全部篩選出來,放到乙個集合裡。篩選好以後,當然可以把這些點兩兩求距離去更新d了,不過這樣還是很慢,萬一滿足條件的點很多呢。這裡還得繼續優化。

首先把這些點按y座標排序。假設排序好以後有cnt個點,編號為0到cnt-1。那麼我們用0號去和1到cnt-1號的點求一下距離,然後1號和2到cnt-1號的點求一下距離。。。如果某兩個點y軸距離已經超過了d,這次迴圈就可以直接break了,開始從下乙個點查詢了。

至於為什麼要再對y進行一次排序,通過查資料了解到,mid線左面中的任一點p,mid線右邊與其構成最接近點對的候選者的點必定落在乙個d*2d的矩形r中,因此利用上段加粗文字的方法進行檢測就可以求得結果了。可以參考下圖:

// 分治演算法求最近點對

#include#include#includeusing namespace std;

struct point

p[100005];

int a[100005]; //儲存篩選的座標點的索引

int cmpx(const point &a , const point &b)

int cmpy(int &a , int &b) //這裡用的是下標索引

inline double dis(point &a , point &b)

inline double min(double a , double b)

double closest(int low , int high)

sort(a , a + cnt , cmpy); //按y座標進行公升序排序

for(i = 0 ; i < cnt ; ++i) }

return ans;

}int main(void)

return 0;

}

參考:

最接近點對問題

一維最臨近點對 假設我們用x軸上某個點m將s劃分為2個子集s1和s2 基於平衡子問題的思想,用s中各點座標的中位數來作分割點。遞迴地在s1和s2上找出其最接近點對和,並設d min,s中的最接近點對或者是,或者是,或者是某個,其中p3 s1且q3 s2。如果s的最接近點對是,即 p3 q3 由於在s...

最接近的點對問題

一 問題描述 給定平面上n個點,找其中一對點,使得在n個點組成的所有點對中,該點對間的距離最小。二 演算法描述 偽 double cpair point p,int left int right n p.size if n 2 return 0x3f3f3f3f 1 int mid left rig...

一維最接近點對(遞迴分治)

一維情況下的最接近點對 includeusing namespace std include include include include define maxint 1000 templatevoid swap type a,type b templatetype min type a,type...