問題描述:給定平面上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;
}