平面最近點距離問題(分治法)


算法:   

 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))。    

 

 

/** 
最近點對問題,時間復雜度為O(n*logn*logn) 
*/  
#include <iostream>  
#include <cstdio>  
#include <cstring>  
#include <cmath>  
#include <algorithm>  
using namespace std;  
const double INF = 1e20;  
const int N = 100005;  
  
struct Point  
{  
    double x;  
    double y;  
}point[N];  
int n;  
int tmpt[N];  
  
bool cmpxy(const Point& a, const Point& b)  
{  
    if(a.x != b.x)  
        return a.x < b.x;  
    return a.y < b.y;  
}  
  
bool cmpy(const int& a, const int& b)  
{  
    return point[a].y < point[b].y;  
}  
  
double min(double a, double b)  
{  
    return a < b ? a : b;  
}  
  
double dis(int i, int j)  
{  
    return sqrt((point[i].x-point[j].x)*(point[i].x-point[j].x)  
                + (point[i].y-point[j].y)*(point[i].y-point[j].y));  
}  
  
double Closest_Pair(int left, int right)  
{  
    double d = INF;  
    if(left==right)  
        return d;  
    if(left + 1 == right)  
        return dis(left, right);  
    int mid = (left+right)>>1;  
    double d1 = Closest_Pair(left,mid);  
    double d2 = Closest_Pair(mid+1,right);  
    d = min(d1,d2);  
    int i,j,k=0;  
    //分離出寬度為d的區間  保存到tmpt中 
    for(i = left; i <= right; i++)  
    {  
        if(fabs(point[mid].x-point[i].x) <= d)  
            tmpt[k++] = i;  
    }  
    sort(tmpt,tmpt+k,cmpy);  
    //暴力搜索 tmpt中的最短距離
    for(i = 0; i < k; i++)  
    {  
        for(j = i+1; j < k && point[tmpt[j]].y-point[tmpt[i]].y<d; j++)  
        {  
            double d3 = dis(tmpt[i],tmpt[j]);  
            if(d > d3)  
                d = d3;  
        }  
    }  
    return d;  
}  
  
  
int main()  
{  
    while(true)  
    {  
        scanf("%d",&n);  
        if(n==0)  
            break;  
        for(int i = 0; i < n; i++)  
            scanf("%lf %lf",&point[i].x,&point[i].y);  
        sort(point,point+n,cmpxy);  
        printf("%.2lf\n",Closest_Pair(0,n-1));  
    }  
    return 0;  
}  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM