最近点对算法步骤
1.先把所有点按照横坐标的关键字排序
2.选取中线将点分成2份
3.递归的求出左边部分的最近点距离d1,右边的最近点距离d2,取d=min(d1,d2)
4.以中线为界,在左右2边d的范围内寻找点,看是否存在跨越中线的点距离小于d
我们要注意的就是第四步,本来我们是需要n^2的时间,但是由于我们已经知道了左右的最近点距离,所以我们向左搜和向右搜的范围就大大减少了,而且,如果存在2个点的在我们搜的左右范围内,但是其2点的纵坐标之差大于d也可以直接排除了
所以第三步的具体做法就出来啦......
1."删除"所有到中线距离大于d的点.
2.把一边平面内的点按照纵坐标排序
3.对于另外一个平面内的点,找到其纵坐标的差在d以内的点,计算距离取min
就是这样啦

1 #include<bits/stdc++.h> 2 #define ll long long 3 #define FOR(i,a,b) for(register int i=a;i<=b;i++) 4 #define ROF(i,a,b) for(register int i=a;i>=b;i--) 5 using namespace std; 6 int n; 7 const ll N=1000000000000; 8 int tmpt[200100]; 9 struct ss 10 { 11 double x;double y; 12 }pot[200100]; 13 int scan() 14 { 15 int as=0,f=1; 16 char c=getchar(); 17 while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();} 18 while(c>='0'&&c<='9'){as=(as<<3)+(as<<1)+c-'0';c=getchar();} 19 return as*f; 20 } 21 bool cmp(ss i,ss j) 22 { 23 return i.x<j.x; 24 } 25 bool cmp2(int i,int j) 26 { 27 return pot[i].y<pot[j].y; 28 } 29 double dis(int i,int j) 30 { 31 double f=sqrt(double((pot[i].x-pot[j].x)*(pot[i].x-pot[j].x)+(pot[i].y-pot[j].y)*(pot[i].y-pot[j].y))); 32 return f; 33 } 34 double par(int l,int r) 35 { 36 // cout<<"y"<<endl; 37 double d=N; 38 if(l==r) return d; 39 if(l+1==r) return dis(l,r); 40 int mid=(l+r)>>1;//除以2 41 double d1=par(l,mid); 42 double d2=par(mid+1,r); 43 d=min(d1,d2); 44 int k=0; 45 FOR(i,l,r) 46 { 47 if(abs(pot[i].x-pot[mid].x)<=d) 48 { 49 tmpt[++k]=i;//保存位置 50 } 51 } 52 sort(tmpt+1,tmpt+k+1,cmp2); 53 FOR(i,1,k) 54 { 55 FOR(j,i+1,k) 56 { 57 if(pot[tmpt[j]].y-pot[tmpt[i]].y>=d) break; 58 double d3=dis(tmpt[i],tmpt[j]); 59 d=min(d,d3); 60 } 61 } 62 return d; 63 } 64 int main() 65 { 66 // freopen("copy.in","r",stdin); 67 // freopen("copy.out","w",stdout); 68 n=scan(); 69 FOR(i,1,n) 70 { 71 scanf("%lf%lf",&pot[i].x,&pot[i].y); 72 } 73 sort(pot+1,pot+n+1,cmp); 74 double h=par(1,n); 75 printf("%.4lf",h);//求1~n的最近点对 76 return 0; 77 }