经典算法 最近点对问题
题目描述
设 p₁=(x₁, y₁), p₂=(x₂, y₂), …, pₙ=(xₙ, yₙ)
是平面上 n
个点构成的集合 S
,请设计算法找出集合 S
中距离最近的点对。
输入格式
- 多组测试数据。
- 第一行为测试数据组数
n
,其中0 < n ≤ 100
。 - 每组测试数据由两个部分组成:
- 第一行为一个整数
m
,表示该组中点的个数,0 < m ≤ 1000
- 接下来
m
行,每行两个整数x
和y
,表示一个点的坐标,满足0 < x, y ≤ 100000
- 第一行为一个整数
输出格式
- 每组测试数据输出一行,为该组数据中最近点对的距离。
- 距离保留 4 位小数。
输入样例
2
2
0 0
0 1
3
0 0
1 1
1 0
输出样例
1.0000
1.0000
c++代码
#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n, m;
vector<vector<double>> arr;
bool sort_by_x(vector<double> a, vector<double> b) {
return a[0] < b[0];
}
bool sort_by_y(vector<double> a, vector<double> b) {
return a[1] < b[1];
}
double recent_questions(ll l, ll r) {
if (l == r) return DBL_MAX;
if (r - l == 1) return (arr[l][0] - arr[r][0]) * (arr[l][0] - arr[r][0]) + (arr[l][1] - arr[r][1]) * (arr[l][1] - arr[r][1]);
ll mid = (l + r) / 2;
double res = min(recent_questions(l, mid), recent_questions(mid + 1, r));
vector<vector<double>> tem;
for (int i = l; i <= r; i++) {
if ((arr[i][0] - arr[mid][0]) * (arr[i][0] - arr[mid][0]) <= res) tem.push_back({arr[i][0], arr[i][1]});
}
sort(tem.begin(), tem.end(), sort_by_y);
for (int i = 0; i < tem.size(); i++) {
for (int j = i + 1, cont = 0; j < tem.size(); j++, cont++) {
res = min(res, (tem[i][0] - tem[j][0]) * (tem[i][0] - tem[j][0]) + (tem[i][1] - tem[j][1]) * (tem[i][1] - tem[j][1]));
if (cont == 7) break;
}
}
return res;
}
int main() {
scanf("%lld", &n);
while(n--) {
scanf("%lld", &m);
arr = vector<vector<double>>(m, vector<double>(2, 0));
for (int i = 0; i < m; i++) {
scanf("%lf %lf", &arr[i][0], &arr[i][1]);
}
sort(arr.begin(), arr.end(), sort_by_x);
printf("%.4lf\n", sqrt(recent_questions(0, m - 1)));
}
}//by wqs