最近點對-分治


題目描述
  給出二維平面上的n個點,求其中最近的兩個點的距離的一半。
  輸入包含多組數據,每組數據第一行為n,表示點的個數;接下來n行,每行一個點的坐標。當n為0時表示輸入結束,每組數據輸出一行,為最近的兩個點的距離的一半。
  輸入樣例:
    2
    0 0
    1 1
    2
    1 1
    1 1
    3
    -1.5 0
    0 0
    0 1.5
    0
  輸出樣例:
    0.71
    0.00
    0.75
題目解析:
  采用分治的思想,把n個點按照x坐標進行排序,以坐標mid為界限分成左右兩個部分,對左右兩個部分分別求最近點對的距離,然后進行合並。對於兩個部分求得的最近距離d,合並過程中應當檢查寬為2d的帶狀區間是否有兩個點分屬於兩個集合而且距離小於d,最多可能有n個點,合並時間最壞情況下是O(n^2).但是,左邊和右邊中的點具有以下稀疏的性質,對於左邊中的任意一點,右邊的點必定落在一個d*2d的矩形中,且最多只需檢查6個點(鴿巢原理),這樣,先將帶狀區間的點按照y坐標進行排序,然后線性掃描,這樣合並的時間復雜度為O(nlogn)。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;

double MAX=1e10; //定義的最大距離,以在只有一個點的時返回無窮大
int a,b;   //用來記錄下標,與題無關
struct Node{
    double x,y;
    int key;   //關鍵碼,可有可無,與ab有關
};

Node ar[100005],br[100005];

bool cmpx(Node a,Node b){return a.x<b.x;}  //x坐標升序
bool cmpy(Node a,Node b){return a.y<b.y;}  //y坐標升序
double min(double a,double b){return a<b?a:b;}  //返回最小值
double dis(Node a,Node b){return sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2));}  //返回點與點之間的距離

double cal(int s,int e)  //s、e用來表示當前處理的數組中的下標位置
{
    int mid,i,j,tail=0;   //mid表示數組中間的位置下標 ,tail作為計數變量,是用來br數組存儲標號的
    double d;   //d表示點對之間的距離
    if(s==e) return MAX;   //如果只有一個點
    mid=(s+e)/2;
    d=min(cal(s,mid),cal(mid+1,e));  //遞歸求出左右兩邊的最小距離
      //下面是求是否存在左邊的點到右邊某點的距離小於d的點,或者是否存在在右邊的點到左邊某點的距離小於d的點,若是存在,必定處於一個d*2d的矩形中
    for(i=mid;i>=s&&ar[mid].x-ar[i].x<d;i--){   //篩選左邊的點,在中間位置左側d以內的點
        br[tail++]=ar[i];
    }

    for(i=mid+1;i<e&&ar[i].x-ar[mid].x<d;i++)    //同上,篩選右邊的點
    {
        br[tail++]=ar[i];
    }
    sort(br,br+tail,cmpy);                      //對矩形內的點按照y坐標進行排序
    for(i=0;i<tail;i++){              //枚舉矩形內點對之間的距離                   
        for(j=i+1;j<tail&&br[j].y-br[i].y<d;j++){
            if(d>dis(br[i],br[j])){           //更新點的值
                //a=min(br[i].key,br[j].key);
                //b=br[i].key+br[j].key-a;
                d=min(d,dis(br[i],br[j]));   
            }
        }
    }
    return d;                     //返回最小的點對之間的距離
}

int main()
{

    int n;
    while(cin>>n&&n){
        for(int i=0;i<n;i++){
            ar[i].key=i+1;               //關鍵碼賦值
            scanf("%lf %lf",&ar[i].x,&ar[i].y);
        }
        sort(ar,ar+n,cmpx);            //按x對ar排序
        double d=cal(0,n);                       
        printf("%.2lf\n",d/2.0);
    }
    return 0;
}


免責聲明!

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



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