Quoit Design
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 30677 Accepted Submission(s): 8060
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.



若矩形R中有多于6个S中的点,则由鸽舍原理(抽屉原理)易知至少有一个dis×2dis的小矩形中有2个以上S(再次强调是总结合S)中的点。设u,v是这样2个点,它们位于同一小矩形中,则
因此d(u,v)<dis 。这与dis(最小距离)的意义相矛盾。也就是说矩形R中最多只有6个S中的点。图4(b)是矩形R中含有S中的6个点的极端情形。由于这种稀疏性质,对于P1中任一点p,P2中最多只有6个点与它构成最接近点对的候选者。因此,在分治法的合并步骤中,我们最多只需要检查6×n/2=3n对候选者,而不是n^2/4对候选者。我们现在知道对于每个S1中的点p最多只需要检查S2中的6个点(确切的说,是矩形R中的6个S中的点),但是我们并不确切地知道要如何检查。为了解决这个问题,我们可以将所有S2(属于(m,m+dis)区间的)的点投影到垂直线l上。由于能与p点一起构成最接近点对候选者的S2中点一定在矩形R中,并且要满足d(p,q)<dis q∈S2(同意这里的S2指的是(m,m+dis)区域),因此满足条件的点它们在直线l上的投影点距p在l上投影点的距离小于dis,由上面的分析可知,这种投影点不多于6个。因此,若将P1和P2中所有S的点按其y坐标排好序,则对P1中所有点p,对排好序的点列作一次扫描,就可以找出所有最接近点对的候选者,对P1中每一点最多只要检查P2中排好序的相继6个点。
杭电亲测1260MS..(我觉得挺慢的,杭电最快0MS我是不知道怎么做的了..)
#include <cstdio>
#include <algorithm>
#include <cmath>
#define min(A,B) ((A) < (B) ? (A) : (B))
#define maxn 100005
#define INF 9999999.9
using std::sort;
struct toy{
double x,y;
}point[maxn];
int N;
int temp[maxn];
int cmp_xy(struct toy a,struct toy b)
{
if(a.x != b.x)
return a.x < b.x;
return a.y < b.y;
}
int cmp_y(int pre,int next)
{
return point[temp[pre]].y < point[temp[next]].y;
}
double distance(int i,int j)
{
double temp1 = point[i].x - point[j].x;
double temp2 = point[i].y - point[j].y;
return sqrt((temp1) * (temp1) + (temp2) * (temp2));
}
double closet_pair(int left,int right)
{
double dis = INF;
if(left == right)//当前集合只有一个坐标
return dis;
if(left + 1 == right)//当前集合只有两个坐标
return distance(left,right);
int mid = (left + right) / 2;
double dis1 = closet_pair(left,mid);//集合1
double dis2 = closet_pair(mid + 1,right);//集合2
/*两个集合分别递归求集合中的最小距离点对*/
dis = min(dis1,dis2);
/*接下来就应该求虚线区域(mid-dis,mid+dis)...*/
int count = 0 ;/*count代表在满足在虚线区域内的电究竟有几个*/
for(int i = left ; i <= right ; i++)
{
if(fabs(point[mid].x - point[i].x) < dis)
temp[count++] = i;
/*满足在虚线区域内的点是第几个点存到temp中*/
}
sort(temp,temp+count,cmp_y);
/*把在虚线区域内的坐标按照y升序排列*/
/*在区域(mid-dis,mid+dis)内枚举*/
for(int i = 0 ; i < count ; i++)
{
for(int j = i + 1 ; (j < count && point[temp[j]].y - point[temp[i]].y < dis) ; j++)
{
/*point[temp[j]].y - point[temp[i]].y > dis的点肯定不是我们要的*/
double dis3 = distance(temp[i],temp[j]);
if(dis3 < dis)
dis = dis3;
}
}
return dis;
}
int main()
{
while(scanf("%d",&N) != EOF && N)
{
for(int i = 0 ; i < N ; i++)
scanf("%lf%lf",&point[i].x,&point[i].y);
sort(point,point+N,cmp_xy);
double radius = closet_pair(0,N-1) / 2;
printf("%.2lf\n",radius);
}
return 0;
}
本文介绍了一种二分法解决最近点对问题的思路,通过将点集划分并逐步缩小搜索范围,最终求得整个点集中任意两点间最小距离的两倍作为所需铁圈的最大半径。
800

被折叠的 条评论
为什么被折叠?



