構造完全圖 題解
阿新 • • 發佈:2020-08-16
題目連結
分析
假設有如下圖兩個集合 \(x\) & \(y\)。因為要構造一個完全圖,所以應該將\(x\)中的\(s[x]\)個節點與\(y\)中的\(s[y]\)個節點一一連線即連線\(s[x] * s[y] - 1\)(此處減一是為了在後面單獨處理原圖中的\(dis[i].w\))個節點,為了保證此完全圖的最小生成樹所以要用\((s[x] * s[y] - 1) * (dis[i].w + 1)\),最後加上原圖中的\(dis[i].w\)。
程式碼
#include <cstdio> #include <iostream> #include <algorithm> #define LL long long using namespace std; const int MAXN = 1e5 + 5; int n, fa[MAXN], s[MAXN]; LL ans; struct node { int u, v, w; } dis[MAXN]; bool cmp (node x, node y) { return x.w < y.w; } int FindSet(int v) { if (fa[v] == v) { return v; } else { return fa[v] = FindSet(fa[v]); } } bool UnionSet(int v, int u) { int x = FindSet(v); int y = FindSet(y); if (x == y) return 0; else { fa[x] = fa[y]; return 1; } } void Kruskal() { sort (dis + 1, dis + n, cmp); for (int i = 1; i <= n; i++) { s[i] = 1; fa[i] = i; } for (int i = 1; i < n; i++) { int x = FindSet(dis[i].u); int y = FindSet(dis[i].v); if (x == y) continue; ans += (long long)(dis[i].w + 1) * (s[x] * s[y] - 1) + dis[i].w; fa[x] = y; s[y] += s[x]; } printf("%lld\n", ans); } int main() { scanf ("%d", &n); for (int i = 1; i < n; i++) { scanf ("%d %d %d", &dis[i].u, &dis[i].v, &dis[i].w); } Kruskal(); return 0; }