问题
给定二维平面上乱序的n(n > 1)个坐标点,求相距最近的两个坐标点是哪两个点,并且输出最近距离,若答案不唯一,输出任意一组满足情况的结果。
思路
我们已知n个点的坐标,要求距离最近的两个点以及其之间的距离,可以通过以下划分过程
划分过程:
我们可选取一个点,求其左边所有点的最小距离,求其右边所有点的最小距离,还有一种情况就是跨越中间点的两个点的最小距离,由此可以划分处理为三部分。
处理过程:
当一段区域内只有两个点时,两个点的距离就是最小距离;
当一段区域内有三个点时,我们可分别求得三点间的两两距离,通过比较求得最小值;
当区域内大于三个点时,我们又可以找到中间点进行划分递归处理;
对于两个点的位置,我们可通过两个全局变量不断更新得到。
代码实现
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#define MAX 100
int a,b;//记录点的位置
struct point{ //坐标点结构体
int x,y;
}z[MAX];
double distance(point z1,point z2){//求两点间距离
double t=(z1.x-z2.x)*(z1.x-z2.x)+(z1.y-z2.y)*(z1.y-z2.y);
t=sqrt(t);
return t;
}
double fun(point s[],int left,int right ){
double d1,d2,d3;
int mid=(right+left)/2;
int i,j,l=left,h=right;
if(left+1==right){//只有两个点时最小值为这两个点
a=left;
b=right;
return distance(s[left],s[right]);
}
if(left+2==right){//有三个点时,需要查找,两两比较找最小值
//三个点之间的两两距离
a=left+1;
b=right;
d1=distance(s[left],s[right]);
d2=distance(s[left+1],s[right]);
d3=distance(s[left],s[left+1]);
if(d1<d2){
d2=d1;//d2为d1 d2中的最小值
a=left;
b=right;
}
if(d3<d2){
d2=d3;//d2为最小值
a=left;
b=left+1;
}
return d2;
}
//多于三个点则需要划分
d1=fun(s,left,mid);//处理左边
d2=fun(s,mid+1,right);//处理右边
if(d1>d2) d1=d2;//d1是小的值
//寻找跨中间的最小值
while(s[l].x<s[mid].x-d1&&l<=right)
l++;
while(s[h].x>s[mid].x+d1&&h>=left)
h--;
for(i=l;i<=h;i++){
for(j=i+1;j<=h;j++){
if(s[j].y-s[i].y>=d1){
break;
}else{
d3=distance(s[i],s[j]);
if(d3<d1){
d1=d3;
a=i;
b=j;
}
}
}
}
return d1;
}
int main(){
int n,i;
double d=0;
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%d %d",&z[i].x,&z[i].y);
}
d=fun(z,0,n-1);
printf("%g %d %d %d %d\n",d,z[a].x,z[a].y,z[b].x,z[b].y);
return 0;
}