描述
给定n个二维平面上的点,求距离最近的一对点,输出他们的距离。
输入
第一行包含一个正整数n。
接下来n行,每行包含两个整数x,y,表示一个点的坐标。
输出
输出距离最近的一对点的距离,保留两位小数。
样例输入
10
7 9
-8 -1
-3 -1
1 4
-3 9
6 -4
7 5
6 6
-6 10
0 8
样例输出
1.41
样例解释
距离最近的点为7和8,距离为√(7−6)2+(5−6)2=√2≈1.41(7-6)2+(5-6)2=2≈1.41
提示
[分治求最近点对。当然也可以用kdtree,虽然应该会超时。]
一. 伪代码
二. 具体实现
#include <bits/stdc++.h>
using namespace std;
// ================= 代码实现开始 =================
typedef double lf;
typedef long long ll;
const int N = 300005;
// 用于存储一个二维平面上的点
struct ip {
int x, y;
// 构造函数
ip(int x = 0, int y = 0) : x(x), y(y) { }
// 先比较x轴,再比较y轴
bool operator < (const ip &a) const {
return x == a.x ? y < a.y : x < a.x;
}
} a[N], b[N];
// 计算x的平方
ll sqr(const ll &x) {
return x * x;
}
// 计算点a和点b的距离
lf dis(const ip &a, const ip &b) {
return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));
}
lf ans;
//分治求最近点对
//l,r:表示闭区间[l,r]
void solve(int l, int r){
//边界情况
if(r - l <= 1){
if(a[l].y > a[r].y)
swap(a[l], a[r]);
if(l != r)
ans = min(ans,dis(a[l], a[r]));
return;
}
//分治计算两遍
int mid = (l + r) >> 1;
int md = a[mid].x;//中间值
solve(l, mid);
solve(mid + 1, r);
//对y轴进行归并排序
int cnt = 0;
for(int i = l, j = mid + 1; i <= mid || j <= r;){
for(; i <= mid && md - a[i].x >= ans; ++i);
for(; j <= r && a[j].x - md >= ans; ++j);
if(i <= mid && (j > r || a[i].y < a[j].y))
b[cnt++] = a[i++];
else
b[cnt++] = a[j++];
}
//现在b数组
for(int i = 0; i < cnt; ++i)
for(int j = i + 1; j < cnt && b[j].y - b[i].y < ans; ++j)
ans = min(ans, dis(b[i], b[j]));
cnt = 0;
for(int i = l, j = mid + 1; i <= mid || j <=r;){
if(i <= mid &&(j > r || a[i].y < a[j].y))
b[cnt++] = a[i++];
else
b[cnt++] = a[j++];
}
memcpy(a + l, b, sizeof(ip) * cnt);
}
// 计算最近点对的距离
// n:n个点
// X, Y:分别表示x轴坐标和y轴坐标,下标从0开始
// 返回值:最近的距离
double getAnswer(int n, vector<int> X, vector<int> Y) {
for(int i = 0; i < n; ++i)
a[i+1] = ip(X[i], Y[i]);
ans = 1e100;
sort(a + 1,a + 1 + n);
solve(1, n);
return ans;
}
// ================= 代码实现结束 =================