题意是求出所给各点中最近点对的距离的一半(背景忽略)。
用分治的思想,先根据各点的横坐标进行排序,以中间的点为界,分别求出左边点集的最小距离和右边点集的最小距离,然后开始合并,分别求左右点集中各点与中间点的距离,从这些距离与点集中的最小距离比较,求得最小距离,此处可按纵坐标排序,将纵坐标距离已经大于之前最小距离的部分都剪枝。
代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 int n,a[100009]; 4 struct point 5 { 6 double x,y; 7 }p[100009]; 8 bool cmpx(point a,point b) 9 { 10 return a.x < b.x; 11 } 12 bool cmpy(int a,int b) 13 { 14 return p[a].y < p[b].y; 15 } 16 double dis(point a,point b) 17 { 18 return sqrt( (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) ); 19 } 20 double min(double a,double b,double c) 21 { 22 if(a>b) return b>c?c:b; 23 return a>c?c:a; 24 } 25 double fin(int from,int to) 26 { 27 if(from+1 == to ) return dis(p[from],p[to]); 28 if(from+2 == to ) return min(dis(p[from],p[from+1]),dis(p[from],p[to]),dis(p[from+1],p[to])); 29 int mid = (from+to)>>1; 30 double ans = min(fin(from,mid),fin(mid+1,to)); 31 int cnt = 0; 32 for(int i = from; i <= to; i++) 33 if(abs(p[i].x-p[mid].x) <= ans) a[cnt++] = i; 34 sort(a,a+cnt,cmpy); 35 for(int i = 0; i < cnt; i++) 36 for(int j = i+1; j < cnt; j++) 37 { 38 if(p[a[j]].y-p[a[i]].y >= ans) break; 39 ans = min(ans,dis(p[a[i]],p[a[j]])); 40 } 41 return ans; 42 } 43 int main() 44 { 45 while(scanf("%d",&n)&&n) 46 { 47 for(int i = 0; i < n; i++) 48 scanf("%lf %lf",&p[i].x,&p[i].y); 49 sort(p,p+n,cmpx); 50 printf("%.2lf ",fin(0,n-1)/2); 51 } 52 return 0; 53 }
但是呢,开始时本人并不是这么写的,而是求了所有点中最小的横坐标和纵坐标,然后以此为参照点,分别求其他各点到参照点的距离,以距离排序,再求出相邻两点距离的最小值。这么写是上面写法的用时一半左右,尽管 AC 了,但是这么写是不对的......
如图所示,图中的点 1 和点 2 距离比点 1 和点 3 的距离更近,但是第二种方法则是用点 1 和点 3距离与点 3 和点 2 距离中求较小值。(题目的测试数据中可能没有这样的数据吧......)
第二种方法的代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 int n; 4 struct point 5 { 6 double x,y,dis; 7 }st,p[100009]; 8 bool cmp(point a,point b) 9 { 10 if(a.dis!=b.dis) return a.dis < b.dis; 11 return a.x<b.x; 12 } 13 double dist(point a,point b) 14 { 15 return sqrt( (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) ); 16 } 17 int main() 18 { 19 double sml; 20 while(scanf("%d",&n)&&n) 21 { 22 st.x = st.y = 1000000.0; 23 sml = 1000000.0; 24 for(int i = 0; i < n; i++) 25 { 26 scanf("%lf %lf",&p[i].x,&p[i].y); 27 if(p[i].x < st.x) st.x = p[i].x; 28 if(p[i].y < st.y) st.y = p[i].y; 29 } 30 for(int i = 0; i < n; i++) 31 p[i].dis = dist(p[i],st); 32 sort(p,p+n,cmp); 33 for(int i = 1; i < n; i++) 34 if(dist(p[i],p[i-1])<sml) sml = dist(p[i],p[i-1]); 35 printf("%.2lf ",sml/2); 36 } 37 return 0; 38 }