阅读了一下平面最近点对的姿势,直接找了一道裸题来做。看完姿势的时候,我一直想不通合并时要怎么实现只考察最近6个点。。其实看了一下其他人的代码,好像都没有写只考察6个点。另外,每次合并,都要进行一次排序,那么它的真正复杂度是不是nlognlogn呢。。不管怎么样,比暴力快了许多。
#include <iostream> #include <cstring> #include <cstdio> #include <queue> #include <algorithm> #include <stdlib.h> #include <math.h> #include <stack> using namespace std; const int mod=1e9+7; #define type double #define Vector Point const double PI = 3.14159265358979323; //二维点/二维向量 struct Point{ type x,y; Point(){ } Point(type x,type y):x(x),y(y){ } Point operator-(Point other){ return Point(x-other.x,y-other.y); } }; //向量长度 double Length(Vector a){ return sqrt(a.x*a.x+a.y*a.y+0.0); } Point pts[100010]; bool byx(const Point& a,const Point& b){ return a.x<b.x; } bool byy(const Point& a,const Point& b){ return a.y<b.y; } Point tmp[100010]; //最近点对 type Nearest(Point* pts,int l,int r){ if(r-l==2){ return Length(pts[l+1]-pts[l]); } if(r-l==3){ double re=min(Length(pts[l+1]-pts[l]),Length(pts[l+2]-pts[l])); re=min(re,Length(pts[l+2]-pts[l+1])); return re; } int mid = (l+r)>>1; type Minl=Nearest(pts,l,mid); type Minr=Nearest(pts,mid,r); type re = min(Minl,Minr); int cnt=0; int pos; //tmp暂存分割线附近的点 pos=mid-1; while(1){ if(pos<l)break; if(pts[pos].x>pts[mid].x-re){ tmp[cnt++]=pts[pos]; pos--; }else{ break; } } pos=mid; while(1){ if(pos>=r)break; if(pts[pos].x<pts[mid].x+re){ tmp[cnt++]=pts[pos]; pos++; }else{ break; } } //感觉有点耍流氓,能不能不排序 sort(tmp,tmp+cnt,byy); //通过y排序 for(int i=0;i<cnt;i++){ for(int j=i+1;j<cnt;j++){ if(tmp[j].y-tmp[i].y>re)break; re=min(re,Length(tmp[j]-tmp[i])); } } return re; } int main(){ int n; while(cin>>n){ if(n==0)break; for(int i=0;i<n;i++){ scanf("%lf%lf",&pts[i].x,&pts[i].y); } sort(pts,pts+n,byx); double ans = Nearest(pts,0,n); printf("%.2f\n",ans/2); } return 0; }