/* Copyright by ZhongMing-Bian Jan,6,2010 */
/* 分治法解决最小套圈问题 */
/* Jan,11 debug ;input question */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define MAX_POINTS 100000 /*坐标点数的最大值 */
#define MAX_TEST 100 /*最大测试次数*/
typedef struct { /*定义坐标点*/
float x;
float y;
}Point;
float dist(Point a, Point b) { /*求两个坐标点之间的距离*/
return sqrt((float)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
float Nearest(Point* points, int n){ /*求最小距离*/
float temp1,temp2,temp3,temp,nearest;
float left,right,d; /*当n小于4时,T(n)=O(1);*/
int i,j;
if(n==1) return 999999999; /*一个点情形,返回值模拟无穷*/
if(n==2) return dist(points[0], points[1]); /*两个点情形*/
if(n==3){ /*三个点情形*/
temp1=dist(points[0], points[1]);
temp2=dist(points[0], points[2]);
temp3=dist(points[1], points[2]);
return temp3<((temp1<temp2)?temp1:temp2)?temp3:((temp1<temp2)?temp1:temp2);
}
/*多于3点的情形,用分治法*/
left=Nearest(points,n/2); /*递归求解*/
right=Nearest(&points[n/2],n-n/2);
d=left<right?left:right;
/*综合中间带求得最小距离*/
nearest=d;
for(i=0;i<n/2;i++)
/* 通过扫描子集一中每个点检查子集二中与其距离在d之内的
所有点(最多6个)以完成合并*/
for(j=n/2;j<n&&(fabs(points[j].y-points[i].y)<d);j++){
temp=dist(points[i],points[j]);
nearest=nearest<temp?nearest:temp;
}
return nearest;
}
int compx(const void* a, const void* b) {
/*实现按x排序*/
return ((Point*)a)->x-((Point*)b)->x;
}
int compy(const void* a, const void* b) {
/*实现按y排序*/
return ((Point*)a)->y-((Point*)b)->y;
}
void main() {
int i,j=0,numPoints;
Point points[MAX_POINTS];
float result[MAX_TEST]; /*记录结果*/
for(i=0;i<MAX_TEST;i++) result[i]=-1;
printf("请输入数据:/n");
while(1){ /*进行多次测试*/
loop: scanf("%d", &numPoints);
if(!numPoints) break;
if(numPoints<0||numPoints>MAX_POINTS) {
printf("Error!/n"); /*容错处理*/
goto loop;
}
for(i=0; i<numPoints; i++) /*输入点的数量及点的坐标值*/
scanf("%f %f", &points[i].x, &points[i].y);
/*预排序,在使用分治法之前,预先将S中的n个点依其y坐标排序好。*/
qsort(points, numPoints, sizeof(Point), compx);
qsort(points, numPoints/2, sizeof(Point), compy);
qsort(points+numPoints/2, numPoints-numPoints/2, sizeof(Point), compy);
result[j]=Nearest(points, numPoints)/2;
j++;
}
i=0;
printf("/n最短距离分别为:/n");
while(result[i]!=-1) /*输出测试结果*/
printf("%.2f/n",result[i++]);
}