#include <algorithm> #include <iostream> #include <vector> #include <iomanip> #include <cmath> #include <numeric> // 用于并查集初始化 using namespace std; struct Point { int i; double x; double y; }; struct Edge { int a; int b; double distance; // Edge(int x, int y, double d):a(x),b(y),distance(d) {} bool operator<(const Edge& other) const { return distance < other.distance; } }; // 并查集 class UnionFind { public: vector<int> parent; UnionFind(int n): parent(n) { // iota(): 为parent容器填充递增的序列,从0开始递增 iota(parent.begin(), parent.end(), 0); } // 找x的根,如果parent[x]==x表示自己就是根,不等于就继续找父亲的根, int find(int x) { return parent[x]==x ? x : parent[x]=find(parent[x]); } bool unite(int x, int y) { x = find(x); y = find(y); if (x==y) return false; parent[y] = x; return true; } }; /* bool mySort(const Edge& e1, const Edge& e2) { return e1.distance<e2.distance; } */ int main() { int num; while (cin >> num) { // 注意 while 处理多个 case vector<Point> points(num); for (int i = 0; i<num; i++) { points[i].i = i; cin >> points[i].x >> points[i].y; } vector<Edge> edges; int cur = 0; for (int i = 0; i<num; i++) { for (int j = i+1; j<num; j++) { double dx = points[i].x - points[j].x; double dy = points[i].y - points[j].y; double dis = sqrt(dx*dx + dy*dy); edges.push_back({points[i].i, points[j].i, dis}); } } sort(edges.begin(), edges.end()); // Kruskal算法求最小生成树 UnionFind uf(num); double sum = 0.0; for (const Edge& e: edges) { if (uf.unite(e.a, e.b)) { sum += e.distance; } } /* bool flag[101] = {false}; for (int i = 0; i<edges.size(); i++) { if (flag[edges[i].a] && flag[edges[i].b]) { //表示边上的2个点在里面 continue; } else { flag[edges[i].a] = true; flag[edges[i].b] = true; sum += edges[i].distance; } } */ cout << setiosflags(ios::fixed) << setprecision(2) << sum << endl; // for (int i = 0; i<edges.size(); i++) { // cout << edges[i].distance << " "; // } } } // 64 位输出请用 printf("%lld")