最接近点对问题(递归与分治)

这篇博客介绍了如何使用递归与分治策略解决二维平面上寻找最接近点对的问题。作者给出了C++代码实现,通过排序和中位数分割点集,逐步找到最小距离的点对。程序包括对点集合的左右子集进行处理,并输出最接近点对及其距离。
摘要由CSDN通过智能技术生成

算法分析与设计的一次实验题,因为输出需要输出最接近的点对,所以这里卡住了好久,这里挂一下代码记录一手。
【问题描述】给定二维平面上n个点,找其中的一对点,使得在n个点组成的所有点对中,该点对间的距离最小。使用递归与分治策略求解二维平面上的最接近点对问题。假设所有点的集合为S,m为S中所有点的x坐标的中位数,垂直线x=m将集合S均匀分割为左右两个子集合S1和S2。

【输入形式】在屏幕上输入点的个数,以及所有点的x和y坐标。

【输出形式】第一次分割时,将所有点集合S分割为左右两个子集合S1和S2,分别输出左右子集合S1和S2,以及所有点集合S的最接近点对的距离以及最接近点对。

【样例输入】

10

-15.4 -57.3

13.2 30.1

-87.5 93.2

47.6 -12.7

94.7 61.5

56.8 -57.1

27.8 43.5

-28.1 19.0

-96.2 47.5

55.5 -93.3

【样例输出】

42.8

-28.1 19.0

13.2 30.1

36.2

55.5 -93.3

56.8 -57.1

19.8

13.2 30.1

27.8 43.5
【样例说明】

输入:10个点,后续每行为每一点的x和y坐标。

输出:左右子集合S1和S2,以及所有点集合S的最接近点对的距离以及最接近点对。例如,前面三行中,S1的最接近点对的距离为42.8,最接近点对的x和y坐标分别为(-28.1,19.0)和(13.2,30.1)。输出最接近点对坐标时,先输出的点的x坐标小于后输出点的x坐标。中间三行和最后三行分别为子集合S2和集合S的最接近点对的距离以及最接近点对。

如下图所示,子集合S1点以蓝色表示,子集合S2以绿色表示。蓝色连线为子集合S1最接近点对间的线段;绿色连线为子集合S2最接近点对间的线段;紫色连线为集合S最接近点对间的线段。
在这里插入图片描述

下面就是代码了,有点乱,见谅。

#include<iostream>
#include<vector>
#include<algorithm>
#include<iomanip>
#define inf 20000 //这个指那个最大的无穷值,我认为20000够用了,再大的数据建议直接设无穷
using namespace std;
int n;
double minj;
struct point
{
	double x;
	double y;
};
point vec[1000];
point jilu[2];
bool sortBy_x(point point1, point point2) //根据x坐标从小到大排序
{
	if (point1.x == point2.x)
		return point1.y < point2.y;
	return point1.x < point2.x;
}
bool sortBy_y(point point1, point point2)    //根据纵坐标从小到大排序
{
	return point1.y < point2.y;
}
double getDistance(point &point1, point &point2)
{
	double dis_x = point1.x - point2.x;
	double dis_y = point1.y - point2.y;
	return sqrt(dis_x*dis_x+dis_y*dis_y);
}
double getMin(int low, int high)
{
	/*if(low==0&&high==(n-1)/2)flag=2;
	if(low==((n-1)/2+1)&&high==n-1)flag=3;
	if(low==0&&high==n-1)flag=4;*/
	if (high - low == 1)    //2个结点
	{ 
	    if(getDistance(vec[low], vec[low + 1])<minj)
	    {
	    	jilu[0]=vec[low];
	    	jilu[1]=vec[low+1];
	    	minj=getDistance(vec[low],vec[low+1]);
		}
		return getDistance(vec[low],vec[low + 1]);
	}	
	else if (high - low == 2)        //3个结点
	{
		double dist1= getDistance(vec[low], vec[low + 1]);
		double dist2 = getDistance(vec[low], vec[low + 2]);
		double dist3 = getDistance(vec[low+1], vec[low + 2]);
        if(dist1<=dist2&&dist1<=dist3&&dist1<minj)
	    {
	    	jilu[0]=vec[low];
	    	jilu[1]=vec[low+1];
	    	minj=getDistance(vec[low],vec[low+1]);
		}
		if(dist2<=dist1&&dist2<=dist3&&dist2<minj)
	    {
	    	jilu[0]=vec[low];
	    	jilu[1]=vec[low+2];
	    	minj=getDistance(vec[low],vec[low+2]);
		}
		if(dist3<=dist2&&dist3<=dist1&&dist3<minj)
	    {
	    	jilu[0]=vec[low+1];
	    	jilu[1]=vec[low+2];
	    	minj=getDistance(vec[low+1],vec[low+2]);
		}
		return min(min(dist1, dist2), dist3);
	}
	else
	{
		int mid = (low + high) / 2;
		double left_min = getMin(low, mid);
		double right_min = getMin(mid + 1, high);
		double d = min(left_min,right_min);
		point res[1000];
		int i,j;
		int ans=0;
		for (i = low; i <= high; i++)        //遍历一遍数组,得到与横坐标与  中点横坐标距离在d以内的点
		{
			if (fabs(vec[i].x - vec[mid].x) < d)
				res[++ans]=vec[i];
		}
		sort(res+1,res+ans+1,sortBy_y);      //根据纵坐标从小到大排序

		for (i = 1; i <ans; i++)
		{
			for (j = i + 1; j <ans+1; j++) 
			{
				if (res[j].y - res[i].y >= d)
					break;
				double dp = getDistance(res[i], res[j]);
				if (dp < d)
				{
					d = dp;
				}
				if(dp<minj)
				{
					jilu[0]=res[i];
					jilu[1]=res[j];
					minj=dp;
				}
			}
		}
		return d;
	}
}
int main()
{
	cin >> n;     //输入点的个数

	for (int i = 0; i < n; i++)
	{
		cin >> vec[i].x >> vec[i].y;
	}
	sort(vec,vec+n, sortBy_x);
	minj=inf;
	cout<<fixed<<setprecision(1)<<getMin(0, (n-1)/2)<<endl;
	if(jilu[0].x>jilu[1].x)
	{
		point t1;
		t1=jilu[0];
		jilu[0]=jilu[1];
		jilu[1]=t1;
	}
	cout<<jilu[0].x<<" "<<jilu[0].y<<endl;
	cout<<jilu[1].x<<" "<<jilu[1].y<<endl;
	jilu[0].x=0;
	jilu[0].y=0;
	jilu[1].x=0;
	jilu[1].y=0;
	minj=inf;
	cout<<fixed<<setprecision(1)<< getMin(((n-1)/2+1), (n-1))<<endl;
	if(jilu[0].x>jilu[1].x)
	{
		point t2;
		t2=jilu[0];
		jilu[0]=jilu[1];
		jilu[1]=t2;
	}
	cout<<jilu[0].x<<" "<<jilu[0].y<<endl;
	cout<<jilu[1].x<<" "<<jilu[1].y<<endl;
	jilu[0].x=0;
	jilu[0].y=0;
	jilu[1].x=0;
	jilu[1].y=0;
	minj=inf;
	cout<<fixed<<setprecision(1)<< getMin(0, n-1) << endl; 
	if(jilu[0].x>jilu[1].x)
	{
		point t3;
		t3=jilu[0];
		jilu[0]=jilu[1];
		jilu[1]=t3;
	} 
    cout<<jilu[0].x<<" "<<jilu[0].y<<endl;
	cout<<jilu[1].x<<" "<<jilu[1].y<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值