分治就是了.
类似于分治找最近/远点对.
CODE
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-13;
const int MAXN = 200005;
const double INF = 1e15;
#define sqr(x) ((x)*(x))
struct Point {
double x, y;
Point(){}
Point(double x, double y):x(x), y(y){}
inline friend double dist(const Point &A, const Point &B) {
return sqrt(sqr(A.x-B.x) + sqr(A.y-B.y));
}
inline friend double S_tri(const Point &A, const Point &B, const Point &C) {
return dist(A, B) + dist(A, C) + dist(B, C);
}
}a[MAXN];
inline bool cmpx(const Point &A, const Point &B) { return A.x < B.x; }
inline bool cmpy(const Point &A, const Point &B) { return A.y < B.y; }
int n;
double solve(int l, int r) {
if(r-l < 2) return INF;
if(r-l == 2) return S_tri(a[l], a[l+1], a[l+2]);
int mid = (l + r) >> 1; double X = a[mid].x;
double re = min(solve(l, mid-1), solve(mid+1, r));
int st = l, ed = r;
while(X-a[st].x > re/2) ++st;
while(a[ed].x-X > re/2) --ed;
sort(a + st, a + ed + 1, cmpy);
for(int i = st; i <= ed; ++i)
for(int j = i+1; j <= ed; ++j)
if(dist(a[i], a[j]) + eps > re/2) break; //剪枝必须加
else for(int k = j+1; k <= ed; ++k)
if(dist(a[i], a[k]) + eps > re/2) break;
else re = min(re, S_tri(a[i], a[j], a[k]));
sort(a + st, a + ed + 1, cmpx);
return re;
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%lf%lf", &a[i].x, &a[i].y);
sort(a + 1, a + n + 1, cmpx);
printf("%.6f
", solve(1, n));
}