算法设计——二维最接近点对问题(递归分治)

问题

给定二维平面上乱序的n(n > 1)个坐标点,求相距最近的两个坐标点是哪两个点,并且输出最近距离,若答案不唯一,输出任意一组满足情况的结果。

思路

我们已知n个点的坐标,要求距离最近的两个点以及其之间的距离,可以通过以下划分过程
划分过程:
我们可选取一个点,求其左边所有点的最小距离,求其右边所有点的最小距离,还有一种情况就是跨越中间点的两个点的最小距离,由此可以划分处理为三部分。
处理过程:
当一段区域内只有两个点时,两个点的距离就是最小距离;
当一段区域内有三个点时,我们可分别求得三点间的两两距离,通过比较求得最小值;
当区域内大于三个点时,我们又可以找到中间点进行划分递归处理;
对于两个点的位置,我们可通过两个全局变量不断更新得到。

代码实现

#include
#include
#include
#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;
}

你可能感兴趣的:(算法设计,递归,分治)