給定 N (≤ 100,000) 個平面點,找到最近點對距離,保留兩位小數。多測試用例,N=0 結束。若有重合點,距離為 0。
在 d×2d 的矩形區域內,若點對距離 ≥ d,最多容納 8 個點(4×2 網格)。故按 y 序掃描時,每點只需與後 7 個點計算距離。
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int MAXN = 100005;
struct Point { double x, y; } p[MAXN], tmp[MAXN];
bool cmpX(const Point& a, const Point& b) { return a.x < b.x; }
bool cmpY(const Point& a, const Point& b) { return a.y < b.y; }
double dist(const Point& a, const Point& b) {
double dx = a.x - b.x, dy = a.y - b.y;
return sqrt(dx*dx + dy*dy);
}
double closest(int l, int r) {
if (l >= r) return 1e20;
if (l + 1 == r) return dist(p[l], p[r]);
int mid = (l + r) >> 1;
double midX = p[mid].x;
double d = min(closest(l, mid), closest(mid+1, r));
// 合併按 y 排序
merge(p+l, p+mid+1, p+mid+1, p+r+1, tmp, cmpY);
copy(tmp, tmp + (r-l+1), p+l);
// 檢查橫跨中線的點
int cnt = 0;
static Point strip[MAXN];
for (int i = l; i <= r; ++i)
if (fabs(p[i].x - midX) < d)
strip[cnt++] = p[i];
for (int i = 0; i < cnt; ++i)
for (int j = i+1; j < cnt && strip[j].y - strip[i].y < d; ++j)
d = min(d, dist(strip[i], strip[j]));
return d;
}
int main() {
int n;
while (scanf("%d", &n) == 1 && n) {
for (int i = 0; i < n; ++i)
scanf("%lf%lf", &p[i].x, &p[i].y);
sort(p, p+n, cmpX);
double ans = closest(0, n-1);
printf("%.2f\n", ans);
}
return 0;
}