P1429 平面最近点对(加强版)
知识点: 分治
原题面:Luogu
扯
?随机旋转一个角度是个什么玩意啊
题意简述
给定 \(n\) 个二维平面上的坐标,求最小的欧几里得距离。
\(1\le n\le 2\times 10^5\)。
分析题意
数据范围不是那么喜人,一个 \(\log\) 可过,考虑先固定一维,按横坐标排序后分治。
对于一个区间 \([l,r]\) 内的点对,递归处理左右半边内部的点对,仅考虑跨区间点对的贡献。
将当前统计到的,最小的欧几里得距离 记为 \(ans\),设为全局变量。
考虑跨分界线的点对的贡献。
显然距离不小于 \(ans\) 的点对,必然是没有贡献的。
距离 \(<ans\) 的点对,其横坐标之差一定 \(<ans\)。
又已按照横坐标进行了排序,考虑找到 最远的 与分界线横坐标差 \(<ans\) 的 跨区间的点对,它们及夹在它们之间的点对,都有可能对答案有贡献。
这样的点对可以简单二分获得,统计跨分界线的点对的贡献时,仅需统计它们两两之间的距离即可。
复杂度比较玄学,但是跑得飞快。
代码实现
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstring>
#define ll long long
const int kMaxn = 2e5 + 10;
const double kInf = 1e9 + 2077;
//=============================================================
struct Node {
double x, y;
bool operator < (const Node &sec_) const {
return x < sec_.x;
}
} node[kMaxn];
int n, llast, rlast;
double ans = kInf;
//=============================================================
inline int read() {
int f = 1, w = 0;
char ch = getchar();
for (; !isdigit(ch); ch = getchar())
if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
return f * w;
}
void Getmin(double &fir_, double sec_) {
if (sec_ < fir_) fir_ = sec_;
}
double distance(int i_, int j_) {
double xi = node[i_].x, yi = node[i_].y;
double xj = node[j_].x, yj = node[j_].y;
return sqrt((xi - xj) * (xi - xj) + (yi - yj) * (yi - yj));
}
int Query(int l_, int mid_node, int r_) {
llast = mid_node + 1;
rlast = mid_node;
double mid_nodex = node[mid_node].x;
for (int l = l_, r = mid_node; l <= r; ) {
int mid = (l + r) / 2;
if (node[mid].x + ans > mid_nodex) {
llast = mid;
r = mid - 1;
} else {
l = mid + 1;
}
}
for (int l = mid_node + 1, r = r_; l <= r; ) {
int mid = (l + r) / 2;
if (node[mid].x - ans < mid_nodex) {
rlast = mid;
l = mid + 1;
} else {
r = mid - 1;
}
}
}
void Solve(int l_, int r_) {
if (l_ == r_) return ;
int mid_node = (l_ + r_) / 2;
Solve(l_, mid_node); Solve(mid_node + 1, r_);
Query(l_, mid_node, r_);
for (int l = llast; l <= mid_node; ++ l) {
for (int r = rlast; r > mid_node; -- r) {
Getmin(ans, distance(l, r));
}
}
}
//=============================================================
int main() {
n = read();
for (int i = 1; i <= n; ++ i) {
scanf("%lf %lf", &node[i].x, &node[i].y);
}
std :: sort(node + 1, node + n + 1);
Solve(1, n);
printf("%.4lf", ans);
return 0;
}
作者@Luckyblock,转载请声明出处。