hdu-1007-Quoit Design-求最小点距离、分治思想

Quoit Design

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 46994    Accepted Submission(s): 12282


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.
 

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
 

Author
CHEN, Yue
 

Source

Code
 /*
 首先我们最朴素的思想是每两个不同的进行比较,然后找出最小的距离,但是显然会超时,作为一个复杂度为O(N^2)的算法
 这个题目的主要思想是分而治之,我们把所有顶点按照x的大小递增排列,然后分为n/2和n-n/2两个部分,那么我们所求结果必然小于等于这两段的结果
 因为我们没有考虑左半端中的点和右半段的点的距离有可能会更加短,如果我们再去分别遍历的话,复杂度变化不大,那么我们去考虑什么样的点才可能是
 满足这种条件的,我们可以想到,在左半端中与n/2这个点横坐标相距距离必然比之前两段都要小才可能满足条件,这样我们便可以筛选出一部分满足条件的点集

 第二步我们利用类似的思想通过对y的排序,两个点如果满足条件也是必然满足纵坐标之差小于之前求的两段最小值的,后面大于此距离的完全不可能是结果,
 当然在代码中比较的是每步已经求得的最小值
 */
 #include <cstdio>
 #include <iostream>
 #include <cmath>
 #include <algorithm>

 using namespace std;
 const double INF(1e7);
 struct node
 {
     double x,y;
 };
 const int maxn(1e5 + 10);
 node points[maxn],*py[maxn];
 bool cmp_x(node a,node b)
 {
     return a.x < b.x;
 }
 bool cmp_y(node * a,node *b)
 {
     return a->y < b->y;
 }
 double dis(node a,node b)
 {
     return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
 }
 double dis(node* a,node* b)
 {
     return (a->x - b->x) * (a->x - b->x) + (a->y - b->y) * (a->y - b->y);
 }
 double divide_conquer(int _left,int _right)
 {
     if(_left == _right)/*如果说是一个点,比如对于三个点的右半段是一个点,我们求出来是没有意义的,所以我们返回INF,通过min()使其失去影响*/
     {
         return INF;
     }
     if(_left + 1 == _right)//最小的有意义段,直接返回距离平方和
     {
         return dis(points + _left,points + _right);
     }
     int _mid = (_left + _right) >> 1;
     double ans = min(divide_conquer(_left,_mid),divide_conquer(_mid + 1,_right));//两段最小值或者更小才可能是最终结果
     int cnt = 0;
     double tmp;
     for(int i = _left;i <= _right;i++)//筛选出距离满足条件的点
     {
         tmp = points[i].x - points[_mid].x;
         if(tmp < ans && tmp > -ans)
         {
             py[cnt++] = points + i;
         }
     }
     sort(py,py + cnt,cmp_y);// order by y asc
     for(int i = 0;i < cnt;i++)
     {
         for(int j = i + 1;j < cnt;j++)
         {
             tmp = py[j]->y - py[i]->y;
             if(tmp < ans)//每次寻找可能的点,注意到每次比较的是已经求的的最小值
             {
                 ans = min(ans,dis(py[i],py[j]));
             }
             else    //后面的y轴距离已经超了,距离更不可能小了
                break;
         }
     }
     return ans;
 }
 int main()
 {
     int n;
     while(scanf("%d",&n),n)
     {
         for(int i = 0 ;i < n;i++)  //read data
         {
             scanf("%lf%lf",&points[i].x,&points[i].y);
         }
         sort(points,points + n,cmp_x); //order by x asc
         double ans = divide_conquer(0,n-1); 
         printf("%.2f\n",sqrt(ans) / 2);
     }
     return 0;
 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值