杭电ACM——1007最近点对问题

首先介绍下二分法查找,又叫对分查找:

        给定一个整数X 和整数A0,A1,A2,.............An-1, 后者已经预先排序并在内存中,求使得Ai = X 的下标i,如果X不在数据中,则返回i = -1。

      一个好的策略是验证X是否是居中的元素,如果是,则答案就找到了,如果X小于居中元素,那么我们可以用同样的策略于居中居中元素左边已经排序的子序列;同理,如果X大于居中元素,那么我们检查数据的右半部分。

代码:

int BinarySearch(const int A[], int X, int N)
{
	int Low, Mid, High;

	Low = 0;
	High = N-1;

	while(Low <= High)
	{
		Mid = (Low + High)/2;
		if(A[Mid] < X)
			Low = Mid + 1;
		else
			if(A[Mid] > X)
				High = Mid -1;
			else
				return Mid;
	}
	return -1;
}

 

这里是给出了一系列点的坐标,所以不能直接用二分法,因为如果将每个点之间距离求出来排序的话,就没有用二分法的必要了,因为已经直接得到结果了,这里用的是分治法。用递归的方法将区间不断减半,直到求出这个区间里个点之间的最小值。

这里还用到了一个数学判断,在判断区间的中间点的左点和右点之间的距离时,两个点(X1,Y1)、(X2,Y2)之间的横坐标的差,纵坐标的差和两点之间的距离构成一个直角三角形,如果(|X2-X1|)- minDistance = a >0, 则 根号下(X2-X1)^2 +(Y2 -Y1)^2 = 根号下(minDistance + a)^2 +(Y2-Y1)^2    可定会大于minDistance, 所以必须满足横坐标的距离和纵坐标的距离都小于minDistance 的两个点才能求最小距离

 
 

#include<iostream>
#include<algorithm> 
#include<cmath>

using namespace std;

static const int MAXNUM=100000;

struct Point
{ 
	double x,y;
}arrP[MAXNUM],arrX[MAXNUM],arrY[MAXNUM];
/*
* arrP[] 的元素是所有的测试点;
* arrX[] 的元素是元素的点的横坐标与中间点的横坐标的距离小于其二分之一范围内的点的最小距离的元素
* arrY[] 的元素是元素的点的纵坐标与中间点的纵坐标的距离小于其二分之一范围内的点的最小距离的元素
*/

bool CompX(Point a,Point b)
{
	if(a.x==b.x)  //如果X轴相等则比较Y轴
		return a.y<b.y;   //a 小于 b 则返回1 ;a 大于 b 则返回-1
	return a.x<b.x;
}

#if 1
bool CompY(Point a,Point b)
{
	if(a.y==b.y)  
		return a.x<b.x; 
	return a.y<b.y;
}
#endif

double GetDistance(Point a,Point b)
{ 
	return sqrt(pow(a.x-b.x,2.0)+pow(a.y-b.y,2.0));
}

/*
* 两个区间(l, middle),(middle+1, r) 分别对应的最小距离 a, b的比较
*/
double MinDistance(double a,double b)  
{ 
	return a<=b ? a : b;
}

double GetMinDistance(int l,int r)
{ 
	if(l==r)   //only one point 
		return 0; 
	else if(l+1==r)  //only two points  
		return GetDistance(arrP[l],arrP[r]); 
	else if(l+2==r)  //only three points 
	{
		double tmp1=GetDistance(arrP[l],arrP[l+1]);  
		double tmp2=GetDistance(arrP[l],arrP[r]);  
		double tmp3=GetDistance(arrP[l+1],arrP[r]);  
		return MinDistance(MinDistance(tmp1,tmp2),tmp3); 
	}
	int middle=(l+r)/2,j=0,k=0; 
	double minDistance=MinDistance(GetMinDistance(l,middle),GetMinDistance(middle+1,r)); 
	
	for(int i=l;i<=r;i++) 
	{
		if(fabs(arrP[i].x-arrP[middle].x)<minDistance)   
			arrX[j++]=arrP[i]; 
	}
	sort(arrX,arrX+j,CompY); 
	middle=(j-1)/2;           //这里我改成了j-1 因为arrX[]数组共j个元素,取中间元素,这里是元素下标,所以应该为(0+(j-1))/2                                                //不过我试了下(j)/2 和 (j+1)/2 (这是网上的答案),都通过了。
	for(int i=0;i<j;i++) 
	{
		if(fabs(arrX[i].y-arrX[middle].y)<minDistance)   
			arrY[k++]=arrX[i]; 
	}
	
	for(int i=0;i<k;i++)  
		for(int j=i+1;j<k;j++)  
		{   
			double tmpDistance=GetDistance(arrY[i],arrY[j]);   
			if(tmpDistance<minDistance)    
				minDistance=tmpDistance;  
		}
		return minDistance;
}

int main()
{
	int n; 
	while(cin>>n && n!=0) 
	{ 
		Point p;  
		double minDistance;  //最小距离

		for(int i=0;i<n;i++)  
		{
			cin>>arrP[i].x>>arrP[i].y;  
		}
		
		sort(arrP,arrP+n,CompX); //按X轴排序 
		
		minDistance=GetMinDistance(0,n-1);  
		
		cout.precision(2);  
		
		cout<<fixed<<minDistance/2<<endl; 
	} 
	return 0;
}


 

你可能感兴趣的:(杭电ACM——1007最近点对问题)