寻找距离最小的点对

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

解决方法:参考编程之美书上所介绍的解法三(分治思想)。

方法框架: 1. 将点按照x座标排序,找到中间点M将所有点分成两个部分,Left和Right。

  1. 找出Left和Right区域分别最小的两点距离DisL, DisR, 则最短距离为DisMin=Min(DisL, DisR);

  2. 在所有节点中找到x属于(M.x-DisMin, M.x+DisMin)的点,然后将这些点(设P表示这个点集)按y座标排序,找这些点中两点之间距离<DisMin的点对。这里对于点a, 有可能与a的距离小于DisMin的点只能在矩形S里阴影里,如下图所示,由抽屉原理,与a有可能距离小于DisMin的点也只能是在a.y最近的6个点中,原理可证与第七个点及其他点距离一定大于DisMin。

  3. 将P中的点依次找最近的6个点(有可能不够6个),然后判断距离是否小于DisMin,若小於则更新DisMin,否则继续,直到P中的点全部遍历结束。

#include "iostream"
#include "vector"
#include "math.h"
#include "algorithm"
using namespace std;

struct point
{
	int x = 0;
	int y = 0;
};

double dis = INT_MAX;
bool compxy(point a, point b)
{
	if (a.x != b.x)
		return a.x < b.x;
	else
		return a.y < b.y;
}
bool compy(point a, point b)
{
	return a.y < b.y;
}
double Count_Distance(const point a, const point b)
{
	double dis = sqrt(pow((a.x - b.x), 2) + pow((a.y - b.y), 2));
	return dis;
}

//统计以mid为中心,长度为2*dis,宽为dis 的矩形中的点,并将其按y排序
double find_cross_dis(point* p, int mid,int left, int right,double dis)
{
	double temp_dis = INT_MAX;
	vector<point> v;
	//分离出宽度为d的区间
	for (int i = left; i <= right; i++)
	{
		if (abs(p[i].x - p[mid].x) < dis)
			v.push_back(p[i]);
	}
	int size = v.size();
	sort(v.begin(), v.end(), compy);
	for (int i = 0; i < size; i++)
	{
		int k = (i + 7) > size ? size :(i + 7);//编程之美上以证明只要比较紧接着的7个点的距离
		for (int j = i + 1; j < k; j++)
		{
			if (abs(p[i].y - p[j].y) < dis)
			{
				temp_dis = Count_Distance(p[i],p[j]);
				dis= min(dis, temp_dis);
			}
		}
	}
	return dis;
}
double find_min_dis(point* p, int left, int right)
{
	if (left == right)
		return INT_MAX;
	if (left + 1 == right)
	{
		double temp = Count_Distance(p[left], p[right]);
		return temp;
	}
		
	int mid = (left + right) >> 1;
	double left_dis = find_min_dis(p, left, mid);
	double right_dis = find_min_dis(p, mid + 1, right);
	double l_r_dis = min(left_dis, right_dis);
	double cross_dis = find_cross_dis(p, mid,left, right,l_r_dis);
	double min_dis = min(l_r_dis, cross_dis);
	
	return min_dis;
}

int main()
{
	int num;//点对的个数
	cin >> num;
	point* p = new point[num];
	for (int i = 0; i < num; i++)
	{
		cin >> p[i].x >> p[i].y;
	}
	sort(p, p + num,compxy);   //按x,y增序排序
	double distance = find_min_dis(p, 0, num - 1);
	cout << distance << endl;
	
	return 1;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章