问题描述:给定平面上N个点的座标,找出距离最近的两个点。
解决方法:参考编程之美书上所介绍的解法三(分治思想)。
方法框架: 1. 将点按照x座标排序,找到中间点M将所有点分成两个部分,Left和Right。
-
找出Left和Right区域分别最小的两点距离DisL, DisR, 则最短距离为DisMin=Min(DisL, DisR);
-
在所有节点中找到x属于(M.x-DisMin, M.x+DisMin)的点,然后将这些点(设P表示这个点集)按y座标排序,找这些点中两点之间距离<DisMin的点对。这里对于点a, 有可能与a的距离小于DisMin的点只能在矩形S里阴影里,如下图所示,由抽屉原理,与a有可能距离小于DisMin的点也只能是在a.y最近的6个点中,原理可证与第七个点及其他点距离一定大于DisMin。
-
将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;
}