题意:给了一张图,有n(1 ≤ n ≤ 750)个点的坐标和m条边(0 ≤ m ≤ 1000),问还要怎么建边才能让所有的点连通,把最小边长总和输出
原题链接:https://vjudge.net/problem/UVA-10397
其实就是一个Kruskal算法的问题,n个点两两之间的边构成边集数组,然后在已有边基础上建立最小生成树即可,这里用的是优先队列
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<cmath> #include<map> using namespace std; typedef pair<int, int> PII; struct Edge { int u, v; double w; Edge(int u, int v, double w) :u(u), v(v), w(w) {} bool operator > (const Edge& B) const { return w > B.w; } }; const int Maxn = 1e3 + 10; int fa[Maxn]; int x[Maxn]; int y[Maxn]; priority_queue<Edge, vector<Edge>, greater<Edge> > pq; int find(int p) { if (p == fa[p]) return p; return fa[p] = find(fa[p]); } bool issame(int u, int v) { return find(u) == find(v); } void unite(int u, int v) { if (!issame(u, v)) fa[find(u)] = find(v); } void Ini() { memset(fa, 0, sizeof(fa)); memset(x, 0, sizeof(x)); memset(y, 0, sizeof(y)); while (!pq.empty()) pq.pop(); } void Input(int n) { for (int i = 1; i <= n; i++) fa[i] = i; for (int i = 1; i <= n; i++) cin >> x[i] >> y[i]; int m; cin >> m; for (int i = 1; i <= m; i++) { int u, v; cin >> u >> v; unite(u, v); } } void solve(int n) { for(int i=1; i<=n ;i++) for (int j = i + 1; j <= n; j++) { int dx = x[i] - x[j]; int dy = y[i] - y[j]; double d = sqrt(dx * dx + dy * dy); pq.push(Edge(i, j, d)); } double ans = 0; while (!pq.empty()) { Edge t = pq.top(); pq.pop(); if (!issame(t.u, t.v)) { ans += t.w; unite(t.u, t.v); } } printf("%.2f\n", ans); } int main() { int n; while (cin >> n) { Ini(); Input(n); solve(n); } return 0; }