编程之美2.11 寻找最近点对

问题:
给定平面上N个点的坐标,找出距离最近的两个点。

方法1:

两两点比较,寻找最近的两个点对,复杂度O(N^2),

方法2:

1、先对N个点的坐标按照X值排序,递归计算左右两部分的最近点对,分别为MinDist(left)、MinDist(right),计算MDist=min (MinDist(left),MinDist(right))

2、找出带状区域。如果一个点对的距离小于MDist,那么他们一定在一个MDist*(2*MDist)的区域内。一个MDist*(2*MDist)的区域最多只有8个点。

3、按照y 坐标,对带状区域内的顶点进行排序。

4、将带状区域的点计算距离与MDist比较。去最小值。

代码如下:

#include<iostream>
#include<algorithm>
#include<iomanip>
#include<math.h>
using namespace std;
#define min(a,b) (((a)<(b))?(a):(b))
struct Point
{
	int x;
	int y;
};
struct rem
{
	int start;
	int end;
}position;
int flag=0;
double Dist_left;
double Dist_right;
double minTemp;
Point *select;
bool operator <(const Point a,const Point b)
{
	if (flag==0)
	{
		return a.x<b.x;
	} 
	else
	{
		return a.y<b.y;
	}
}
double compute_Dist(Point point1,Point point2)
{
	return sqrt((point1.x-point2.x)*(point1.x-point2.x)+(point1.y-point2.y)*(point1.y-point2.y));
}
double Dist(Point point[],int start,int end,double minDist)
{
	int mid,i,j=0,k;
	double a,b,c;
	if ((end-start+1)>3)
	{   
		mid=(end+start)/2;
		Dist_left=Dist(point,start,mid,minDist);
		Dist_right=Dist(point,mid+1,end,minDist);
		minDist=min(Dist_left,Dist_right);
		for (i=start;i<=end;i++)
		{
			if (abs(point[mid].x-point[i].x)<=minDist)
			{
				select[j]=point[i];
				j++;
			}
		}
		//坐标按照y排序
		sort(select,select+j);
		//计算
		for (i=0;i<j;i++)
		{
			for (k=i+1;(k<j)&&k<=(i+7);k++)
			{
				if (compute_Dist(select[i],select[k])<minDist)
				{
					minDist=compute_Dist(select[i],select[k]);
					position.start=i;
					position.end=k;
				}
			}
		}
		return minDist;
	}
	if ((end-start+1)==3)
	{
		a=compute_Dist(point[start],point[start+1]);
		b=compute_Dist(point[start],point[end]);
		c=compute_Dist(point[start+1],point[end]);
		minDist=min(a,b);
		minDist=min(minDist,c);
		if (flag==1)
		{
			flag++;
			minTemp=minDist;
		}
		if (minDist==a)
		{
			if (minDist<=minTemp)
			{
				minTemp=minDist;
				position.start=start;
				position.end=start+1;
			}
		} 
		else
		{
			if (minDist==b)
			{
				if (minDist<=minTemp)
				{
					minTemp=minDist;
					position.start=start;
					position.end=end;
				}
			}
			else
			{
				if (minDist<=minTemp)
				{
					minTemp=minDist;
					position.start=start+1;
					position.end=end;
				}
			}
		}
	} 
	else
	{
		minDist=compute_Dist(point[start],point[end]);
		if (flag==1)
		{
			flag++;
			minTemp=minDist;
		}
		if (minDist<=minTemp)
		{
			minTemp=minDist;
			position.start=start;
			position.end=end;
		}
	}
	return minDist;
}
int main()
{
	int N;
	int i,j=0;
	int k;
	int mid;
	double MinDist;
	Point *point;
	int temp=0;
	double MinDist_left,MinDist_right;
	cout<<"请输入点对的个数:";
	cin>>N;
	point=(Point*)malloc(sizeof(Point)*(N+1));
	select=(Point*)malloc(sizeof(Point)*(N+1));
	cout<<"请输入"<<N<<"个点对:"<<endl;
	for (i=0;i<N;i++)
	{
		cin>>point[i].x;
		cin>>point[i].y;
	}
	cout<<endl;
	sort(point,point+N);
	flag++;
	setprecision(4);//精度为3
	if (N<=3)
	{
		MinDist=Dist(point,0,N-1,MinDist);	
// 		cout<<setprecision(4)<<MinDist<<"....."<<endl;
// 		cout<<point[position.start].x<<" "<<point[position.start].y<<endl;
// 		cout<<point[position.end].x<<" "<<point[position.end].y<<endl;
	}
	else
	{
		//找出左右两部分的MinDist
		mid=(N-1)/2;
		MinDist_left=Dist(point,0,mid,MinDist);
		MinDist_right=Dist(point,mid+1,N-1,MinDist);
		/*cout<<setprecision(4)<<MinDist_left<<"....."<<setprecision(4)<<MinDist_right<<"<<<<>>>"<<min(MinDist_left,MinDist_right)<<endl;*/
		minTemp=min(MinDist_left,MinDist_right);
// 		cout<<point[position.start].x<<" "<<point[position.start].y<<endl;
// 		cout<<point[position.end].x<<" "<<point[position.end].y<<endl;
		//带状区域
		for (i=0;i<N;i++)
		{
			if (abs(point[mid].x-point[i].x)<=minTemp)
			{
				select[j]=point[i];
				j++;
			}
		}
		//坐标按照y排序
		sort(select,select+j);
		//计算
		for (i=0;i<j;i++)
		{
			for (k=i+1;(k<j)&&k<=(i+7);k++)
			{
				if (compute_Dist(select[i],select[k])<minTemp)
				{
					temp++;
					minTemp=compute_Dist(select[i],select[k]);
					position.start=i;
					position.end=k;
				}
			}
		}
	}
	if (temp==0)
	{
		cout<<"最近点对:"<<endl;
		cout<<point[position.start].x<<" "<<point[position.start].y<<endl;
		cout<<point[position.end].x<<" "<<point[position.end].y<<endl;
		cout<<"distance: "<<minTemp<<endl;
	} 
	else
	{
		cout<<"最近点对:"<<endl;
		cout<<select[position.start].x<<" "<<select[position.start].y<<endl;
		cout<<select[position.end].x<<" "<<select[position.end].y<<endl;
		cout<<"distance: "<<minTemp<<endl;
	}
	free(point);
	return 0;
}

程序运行结果:

请输入点对的个数:14
请输入14个点对:
1 8
3 10
5 12
-10 0
-8 0
-7 0
-20 0
-18 0
-14 0
-16 0
-12 0
-5 2
-3 4
-1 6

最近点对:
-8 0
-7 0
distance: 1


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值