问题描述:
给定平面上n个点,找其中的一对点,使得在n个点的所有点对中,该点对的距离最小。
解题步骤:
第一次分割时,将所有点集合S分割为左右两个子集合S1和S2,分别输出左右子集合S1和S2,以及所有点集合S的最接近点对的距离以及最接近点对。
取第n/2个点的x坐标,比较所有在【x-d,x+d】内点的距离,取【x-d,x】内的一点,将该点与x属于【x,x+d】,【y-d,y+d】内的点进行比较(最多个数为6个)。
比较【x-d,x+d】内求得的最短距离与d进行,得出所有点的最邻近点对。
鸽舍原理:由d的意义可知P2中任何2个S中的点的距离都不小于d。由此可以推出矩形R中最多只有6个S中的点。事实上,我们可以将矩形R的长为2δ的边3等分,将它的长为d的边2等分,由此导出6个(d/2)×(2d/3)的矩形
代码
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
struct Point {
double x;
double y;
};
// 计算两个点之间的欧几里得距离
double calculateDistance(Point a, Point b) {
double dx = a.x - b.x;
double dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
//让X进行升序排序
bool comparePointsX(const Point& p1, const Point& p2) {
return p1.x < p2.x;
}
double zuiJingDiandui(vector<Point> points)
{
int n = points.size();
double minDistance;
if (n <= 1)
{
return 0;
}
if (n == 2)
{
double d1 = calculateDistance(points[0], points[1]);
return d1;
}
if (n == 3)
{
double d1 = calculateDistance(points[0], points[1]);
double d2 = calculateDistance(points[1], points[2]);
double d3 = calculateDistance(points[2], points[3]);
return min(min(d1, d2), min(d2, d3));
}
if (n > 3)
{
// 按照x坐标排序
sort(points.begin(), points.end(), comparePointsX);
// 分割点集
int mid = n / 2; // 找到中间点索引
vector<Point> leftPoints(points.begin(), points.begin() + mid); // 分割出左侧的点集
vector<Point> rightPoints(points.begin() + mid, points.end()); // 分割出右侧的点集
// 递归计算左右子集的最近点距离
double leftDistance = zuiJingDiandui(leftPoints);
double rightDistance = zuiJingDiandui(rightPoints);
// 找到左右子集的最小距离
minDistance = min(leftDistance, rightDistance);
// 找到可能跨越子集边界的最近点对
vector<Point> stripPoints;
double midLine = points[mid].x; // 中线的x坐标
for (int i = 0; i < n; i++) {
if (fabs(points[i].x - midLine) < minDistance) { // 将横坐标与中线横坐标距离小于最小距离的点放入stripPoints
stripPoints.push_back(points[i]);
}
}
// 在stripPoints中寻找更小的距离
int stripSize = stripPoints.size();
for (int i = 0; i < stripSize; i++) {
for (int j = i + 1; j < stripSize && (stripPoints[j].y - stripPoints[i].y) < minDistance; j++) {
double distance = calculateDistance(stripPoints[i], stripPoints[j]);
minDistance = min(minDistance, distance);
}
}
}
return minDistance;
}
int main()
{
int N;
cin >> N;
vector<Point> points;
double x, y;
for (int i = 0; i < N; i++)
{
cin >> x >> y;
points.push_back(Point{ x, y });
}
if (zuiJingDiandui(points) == 0)
{
cout << "不存在" << endl;
}
else
cout << zuiJingDiandui(points) << endl;
return 0;
}
结果