参考自《编程之美》169页,大概原理就是把区间分成两部分,然后递归找每一部分中最近的点对,还有一种情况就是这个点对分属于这两部分,然后选两部分中的部分点枚举即可,取其最小值。
//2013-10-21-17.18 #include <stdio.h> #include <algorithm> #include <math.h> #include <iostream> const double INF=1e100; using namespace std; struct node { double x, y; bool flag; }p[200005], tmp[200005]; bool cmpx(node a, node b) { return a.x < b.x; } bool cmpy(node a, node b) { return a.y < b.y; } double dis(node a, node b) { return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y)); } double getans(int l, int r) { double rs = INF; if (l == r) return rs; if (r - 1 == l) { if (p[l].flag == p[r].flag) return rs; return dis(p[l], p[r]); } int mid = (l+r)>>1; rs = getans(l, mid); rs = min(rs, getans(mid+1, r)); int cnt = 1; for (int i = l; i <= r; i++) { if (fabs(p[i].x - p[mid].x) <= rs) tmp[cnt++] = p[i]; } sort(tmp+1, tmp+cnt, cmpy); for (int i = 0; i < cnt; i++) { for (int j = i+1; j < cnt; j++) { if (fabs(tmp[i].y-tmp[j].y) >= rs) break; if (tmp[i].flag != tmp[j].flag) rs = min(rs, dis(tmp[i], tmp[j])); } } return rs; } int main() { int t, n; scanf("%d", &t); while (t--) { scanf("%d", &n); int i = 1; for (; i <= n; i++) { scanf("%lf %lf", &p[i].x, &p[i].y); p[i].flag = false; } n <<= 1; for (; i <= n; i++) { scanf("%lf %lf", &p[i].x, &p[i].y); p[i].flag = true; } sort(p+1, p+n+1, cmpx); printf("%.3lf ", getans(1, n)); } return 0; }