structEdge { int u, v, w; // 存下入边,出边,权值 booloperator < (const Edge &rhs) const// 重载运算符,将权值为第一关键词非降序排序 { if (w != rhs.w) return w < rhs.w; if (u != rhs.u) return u < rhs.u; return v < rhs.v; } }; vector <Edge> graph;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
int pre[N];
intrt(int x) { return pre[x] = (pre[x] == x ? x : rt(pre[x])); }
inlinevoidmerge(int x, int y) { pre[rt(x)] = rt(y); }
inlineboolcheck(int x, int y) { returnrt(x) == rt(y); }
intmain() { // ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n, m; cin >> n >> m; for (int i = 1; i <= m; i++) { int u, v, w; cin >> u >> v >> w; graph.push_back({u, v, w}); // 存边 } sort(graph.begin(), graph.end()); // 排序 ll ans = 0; for (int i = 1; i <= n; i++) pre[i] = i; // 并查集初始化 for (auto t : graph) { auto &[a, b, val] = t; if (check(a, b)) continue; // 如果已经联通,则跳过 ans += val; // 直接加上这两条边的权值 merge(a, b); // 合并该两条边 } bool tag = true; for (int i = 1; i < n; i++) if (rt(i) != rt(i + 1)) tag = false; // 判断是否可以形成连通图 if (tag == false) cout << "orz\n"; else cout << ans; return0; }
Prim 算法
整体思路:
Prim 的思想是将任意节点作为根,再找出与之相邻的所有边中最短的一条边,再将新节点更新并以此节点作为根继续搜,同时维护一个数组作用为已用点到未用点的最短距离,并且一个 bool 数组来记录没有存入生成树的边。实现操作类似 Dijkstra 算法。
核心思路:对于任意一个顶点 v,连接到该顶点的所有边中的一条最短边必然属于最小生成树。
时间复杂度:
朴素:O(n2),堆优化:O(nlogn)(其中 n 表示点数)。
代码实现:
1 2 3 4 5
structEdge { int ver, val; booloperator < (const Edge &rhs) const { return val > rhs.val; } };