//最近点对
//1.分:
// 把所有点递归分到小于等于3个点
// 然后3个点或2个点两两之间Brute force找出最近的两点距离dlf, 和 drg,并返回这两点
//2.并:
// 找出每分界线之间最短的dmid,跟据排序后X序列
// ^
// . . | . . . |
// . .| . . . d
// . . | . . . |
// <-d ->| <-d-> v
//
//
#include <iostream>
#include <algorithm>
#include <cmath>
using std::cin;
using std::cout;
using std::sort;
using std::sqrt;
#define MAX 100
//#define _DEBUG__
struct Point
{
double x;
double y;
};
struct Point_Y
{
int index;
Point point;
};
int n = 0;
Point *X = NULL;
Point_Y * Y = NULL;
bool cmpX(Point a, Point b)
{
return a.x < b.x;
}
bool cmpY(Point_Y a, Point_Y b)
{
return a.point.y < b.point.y;
}
void SortX()
{
if (X != NULL)
sort(X, X + n, cmpX);
#ifdef _DEBUG__
for (int i = 0; i < n; ++i)
cout << "x=" << X[i].x << "y=" << X[i].y << "\n";
#endif
}
void Copy()
{
if (X != NULL && Y != NULL){
for (int i = 0; i < n; ++i){
Y[i].index = i;
Y[i].point.x = X[i].x;
Y[i].point.y = X[i].y;
}
}
}
void SortY()
{
if (Y != NULL)
sort(Y, Y + n, cmpY);
}
double Distance(Point &a, Point &b)
{
return ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
double fabs(double a)
{
return a > 0.0 ? a : -a;
}
void Find_Close_Pair(Point_Y * Y, int low, int hight, Point &node_a, Point &node_b, double &dist)
{
if (hight - low == 1){//2点
node_a = X[low], node_b = X[hight];
dist = Distance(node_a, node_b);
}
else if(hight - low == 2){//3点
if (Distance(X[low], X[low + 1]) < Distance(X[low], X[hight])
&& Distance(X[low], X[low + 1]) < Distance(X[low + 1], X[hight]))
node_a = X[low], node_b = X[low + 1];
else if (Distance(X[low + 1], X[hight]) < Distance(X[low], X[hight]))
node_a = X[low + 1], node_b = X[hight];
else node_a = X[low], node_b = X[hight];
dist = Distance(node_a, node_b);
}
else{//下面运用分治法
//分
int mid = (hight - low) / 2;
Point_Y *XL = new Point_Y[mid + 1];
Point_Y *XR = new Point_Y[mid + 1];
int xl = 0, xr = 0;
mid += low;
for (int i = 0; i < hight - low + 1; ++i){
if (Y[i].index <= mid)
XL[xl++] = Y[i];
else
XR[xr++] = Y[i];
}
Point nal, nbl, nar, nbr;
double distl, distr;
Find_Close_Pair(XL, low, mid, nal, nbl, distl);
Find_Close_Pair(XR, mid + 1, hight, nar, nbr, distr);
if (distl < distr)
node_a = nal, node_b = nbl, dist = distl;
else
node_a = nar, node_b = nbr, dist = distr;
//并
Point *Comb = new Point[hight - low + 1];
int count_comb = 0;
for (int i = 0; i < hight - low + 1; ++i)
if (fabs(X[mid].x - Y[i].point.x) < dist){//找出当前子集合中在离最中间的线(X[m].x)
//横座标小于dist的当前子集合中所有点
Comb[count_comb].x = Y[i].point.x, Comb[count_comb].y = Y[i].point.y;
count_comb++;
}
for (int i = 0; i < count_comb; ++i)//两两之间的距离
for (int j = i + 1; (j < count_comb) && (fabs(Comb[i].y - Comb[j].y) < dist); ++j)
if (Distance(Comb[i], Comb[j]) < dist)
node_a = Comb[i], node_b = Comb[j], dist = Distance(Comb[i], Comb[j]);
delete []XL;
delete []XR;
delete []Comb;
}
}
void Init()
{
for (int i = 0; i < n; ++i){
cin >> X[i].x >> X[i].y;
}
}
void MinClosePair()
{
Init();
SortX();
Copy();
SortY();
Point node_a, node_b;
double dist = 0.0;
Find_Close_Pair(Y, 0, n - 1, node_a, node_b, dist);
#ifdef __DEBUG__
cout << sqrt(dist) << '\n';
cout << "A (" << node_a.x << "," << node_a.y << ")\n";
cout << "B (" << node_b.x << "," << node_b.y << ")\n";
#endif
printf("%.2lf\n", sqrt(dist) / 2.0);
}
int main(void)
{
while (cin >> n){
if (n == 0) break;
X = new Point[n];
Y = new Point_Y[n];
MinClosePair();
delete []X;
delete []Y;
}
return 0;
}
最近点对
最新推荐文章于 2022-05-31 08:38:38 发布