Quoit Design
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 28566 Accepted Submission(s): 7475
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
Author
CHEN, Yue
Source
第一次接触分治法,用分治法求两点间最短距离。
重点是循环递归。
在每一层递归上都有三个步骤:
- 分解:将原问题分解为若干个规模较小,相对独立,与原问题形式相同的子问题。
- 解决:若子问题规模较小且易于解决时,则直接解。否则,递归地解决各子问题。
- 合并:将各子问题的解合并为原问题的解。
AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
bool cmpx(const struct point a,const struct point b);
bool cmpy(const int& a,const int& b);
double mi(double a,double b);
double dis(const point a,const point b);
double dc(int left,int right);
#define N 100005
#define INF 0x3f3f3f3f
using namespace std;
struct point
{
double x;
double y;
}p[N];
int n;
int f[N];
int main()
{
int i;
while(~scanf("%d",&n),n)
{
for(i=0;i<n;i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
double ans;
sort(p,p+n,cmpx);
ans=dc(0,n-1);//这里传的是点的标号
printf("%.2lf\n",ans/2);
}
return 0;
}
bool cmpx(const point a,const point b)
{
return a.x<b.x;
}
bool cmpy(const int& a,const int& b)
{
return p[a].y<p[b].y;
}
double mi(double a,double b)
{
return a>b?b:a;
}
double dis(const point a,const point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double dc(int left,int right)
{
if(left+1==right)//如果只有两个点,则最短距离为两点间距离
return dis(p[left],p[right]);
if(left==right)
return 0;
int mid;
mid=(left+right)/2;//分两段
double dl;
dl=dc(left,mid);
double dr;
dr=dc(mid,right);
double d;
d=mi(dl,dr);
int cnt=0;
for(int i=left;i<=right;i++)
if(fabs(p[mid].x-p[i].x)<=d)
{
f[cnt]=i;//f记录筛完后的点,这样在下面那个循环就可以提高效率,只遍历有效的点
cnt++;
}
sort(f,f+cnt,cmpy);
for(int i=0;i<cnt;i++)
{
for(int j=i+1;j<cnt&&p[f[j]].y-p[f[i]].y<d;j++)//y的差也要小于d
{
double d3=dis(p[f[i]],p[f[j]]);
d=mi(d3,d);
}
}
return d;
}