尋找距離最小的點對

問題描述:給定平面上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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章