今天我與一道題較上了勁,這題名叫最近點對,該題用分治法解答。廢話不多說,貼上題目(來自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;
}