最近點對問題

今天我與一道題較上了勁,這題名叫最近點對,該題用分治法解答。廢話不多說,貼上題目(來自cugboj):
這裏寫圖片描述
題目主要解答步驟爲:
1、將輸入的數優先x升序其次y升序的方法排序;通過sort、qsort或同等效率的排序算法解決;
2、寫出求兩點距離的函數dis(…….)。(參數省略,以下也省略)
3、因爲對於任意區間【l,r】我們可以分爲兩部分,進行三次討論。前兩次討論即【l,mid-1】區間內的最近距離,【mid,r】區間內的最近距離,然後去上述最近距離的最小值d。這兩個區間可以通過遞歸調用解決,邊界條件見步驟五。
4、第三次討論是:對位於【mid-d,mid+d】區間內的點對(該區間內的點對有可能距離小於d)進行距離討論,注意要先按y座標排序,for循環遍歷每個點,循環過程中只需要討論每個點上下距離爲d的點對(即豎直距離大於d時continue)(情況複雜,詳見代碼),最後視情況更新d。
5、遞歸結束條件爲區間內只有兩點或一點,當區間內只有一點時,返回MAXN(自定義的無限大),當區間內有兩點時,返回值爲這兩地點的距離。
貼上ac代碼:

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define MAXN 2147483647
#define DOUM 1e300
class adre
{
    public:
        double x,y;
};
adre adr[100005];
int temp[100005];
int cmp(adre a,adre b)
{
    if(a.x!=b.x) return a.x<b.x;
    else return a.y<b.y;
}
int cmpy(int a,int b)
{
    return adr[a].y<adr[b].y;
}
double dis(adre a,adre b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double closestpoint(int left,int right)
{
    double d1,d;
    int mid=(left+right)>>1;
    if(left+1==right) return dis(adr[left],adr[right]);
    if(left+2==right) return min(dis(adr[left],adr[right]),min(dis(adr[left],adr[left+1]),dis(adr[left+1],adr[right])));
    d=min(closestpoint(left,mid),closestpoint(mid+1,right));
    int i,j,k=0;
    for(i=left;i<=right;i++)
    {
        if(fabs(adr[i].x-adr[mid].x)<=d) temp[k++]=i;
    }
    sort(temp,temp+k,cmpy);
    for(i=0;i<k;i++)
    {
        for(j=i+1;j<k;j++)
        {
            if(adr[temp[j]].y-adr[temp[i]].y>=d) break;
            d1=dis(adr[temp[i]],adr[temp[j]]);
            if(d1<d) d=d1;
        }
    }
    return d;
}
int main()
{
    int n,i,t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i=0;i<n;i++) scanf("%lf %lf",&adr[i].x,&adr[i].y);
        sort(adr,adr+n,cmp);
        printf("%.2f\n",closestpoint(0,n-1));
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章