Problem Description
Have you ever played quoit in a playground? Quoit is a game in which flat rings are pitched at some toys, with all the toys encircled awarded.
In the field of Cyberground, the position of each toy is fixed, and the ring is carefully designed so it can only encircle one toy at a time. On the other hand, to make the game look more attractive, the ring is designed to have the largest radius. Given a configuration of the field, you are supposed to find the radius of such a ring.
Assume that all the toys are points on a plane. A point is encircled by the ring if the distance between the point and the center of the ring is strictly less than the radius of the ring. If two toys are placed at the same point, the radius of the ring is considered to be 0.
In the field of Cyberground, the position of each toy is fixed, and the ring is carefully designed so it can only encircle one toy at a time. On the other hand, to make the game look more attractive, the ring is designed to have the largest radius. Given a configuration of the field, you are supposed to find the radius of such a ring.
Assume that all the toys are points on a plane. A point is encircled by the ring if the distance between the point and the center of the ring is strictly less than the radius of the ring. If two toys are placed at the same point, the radius of the ring is considered to be 0.
Input
The input consists of several test cases. For each case, the first line contains an integer N (2 <= N <= 100,000), the total number of toys in the field. Then N lines follow, each contains a pair of (x, y) which are the coordinates of a toy. The input is terminated by N = 0.
Output
For each test case, print in one line the radius of the ring required by the Cyberground manager, accurate up to 2 decimal places.
Sample Input
2
0 0
1 1
2
1 1
1 1
3
-1.5 0
0 0
0 1.5
0
Sample Output
0.71
0.00
0.75
给你平面上n个点,让你找最近的2个点的距离的一半
经典的分治问题,我们现将点按照x坐标排序,先处理前一半的答案,再处理后一半的答案,两个取最小ans
现在还没完呢,万一一个点在左半边另一个点在右半边呢?这样我们就要更新答案了.我们注意到这样的点肯定满足到中心的点的距离不超过ans
我们暴力搞出这些点,这些点是有可能来更新ans的,我们是不是要将这些点n^2算距离更新呢?这样显然是超时的
我们将这些点按y坐标排序,我们对于第1个点开始求它与第2~cnt个点的y坐标的差值,一旦这个差值大于ans就不用再去比较后面的点了,我们再从第2个点求它与第3~cnt个点的y坐标差,以此类推
这样及时的break就优化了......
谁信啊!!!!其实这涉及到一个点周围能够更新ans的点最多有6个,否则上面ans就不是答案了
代码如下:
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 const int maxn = 1100000; 5 struct point 6 { 7 double x,y; 8 }p[maxn]; 9 int a[maxn]; 10 double dis (point q1,point q2) 11 { 12 return sqrt((q1.x-q2.x)*(q1.x-q2.x)+(q1.y-q2.y)*(q1.y-q2.y)); 13 } 14 bool cmpx (point q1,point q2) 15 { 16 return q1.x<q2.x; 17 } 18 bool cmpy (int q1,int q2) 19 { 20 return p[q1].y<p[q2].y; 21 } 22 int n; 23 double calc (int l,int r) 24 { 25 if (r==l+1) 26 return dis(p[l],p[r]); 27 else if (r==l+2) 28 return min(dis(p[l],p[l+1]),min(dis(p[l+1],p[r]),dis(p[l],p[r]))); 29 else{ 30 int mid = (l+r)/2; 31 double ans = min(calc(l,mid),calc(mid+1,r)); 32 int cnt = 0; 33 for (int i=l;i<=r;++i){ 34 if (p[i].x>=p[mid].x-ans&&p[i].x<=p[mid].x+ans) 35 a[cnt++]=i; 36 } 37 sort(a,a+cnt,cmpy); 38 for (int i=0;i<cnt;++i){ 39 for (int j=i+1;j<cnt;++j){ 40 if (p[a[j]].y-p[a[i]].y>=ans) break; 41 else{ 42 ans = min(ans,dis(p[a[i]],p[a[j]])); 43 } 44 } 45 } 46 return ans; 47 } 48 } 49 int main() 50 { 51 //freopen("de.txt","r",stdin); 52 while (~scanf("%d",&n)){ 53 if (n==0) break; 54 for (int i=0;i<n;++i){ 55 scanf("%lf%lf",&p[i].x,&p[i].y); 56 } 57 sort(p,p+n,cmpx); 58 double ans = calc(0,n-1); 59 printf("%.2f ",ans/2); 60 } 61 return 0; 62 }
精髓就是通过不断二分从指数上将复杂度降下来