Kruskal
先把边按照权值进行排序,用贪心的思想优先选取权值较小的边,并依次连接,若出现环则跳过此边(用并查集来判断是否存在环)继续搜,直到已经使用的边的数量比总点数少一即可。
题目描述
给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz
。
输入格式
第一行包含两个整数 N, M,表示该图共有 N 个结点和 M 条无向边。
接下来 M 行每行包含三个整数 X i , Y i , Z i X_i,Y_i,Z_i Xi,Yi,Zi,表示有一条长度为 Z_i的无向边连接结点 X i , Y i X_i,Y_i Xi,Yi。
输出格式
如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出 orz
。
样例
输入
4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3
输出
7
代码
#include<bits/stdc++.h>
using namespace std;
int N, M, X, Y, Z, ans = 0, cnt = 0;
int mp[5010][5010];
struct Edge {
int u, v, w;
}edge[200010];
int fa[5010];
// 排序规则
inline bool cmp(Edge a, Edge b) {
return a.w < b.w;
}
// 并查集
inline int find(int x) {
while (x != fa[x]) x = fa[x] = fa[fa[x]];
return x;
}
inline void kruskal() {
sort(edge, edge + M, cmp);
for (register int i = 1; i <= M; i++) {
int eu = find(edge[i].u), ev = find(edge[i].v);
if (eu == ev) continue; // 判断是否闭环, 如果出现闭环则不需要该边
ans += edge[i].w; // 将此边计入答案
fa[ev] = eu; // 合并
if (++cnt == N - 1)break; // 完成连通(edge = point - 1)
}
}
int main() {
cin >> N >> M;
// 并查集初始化
for (register int i = 1; i <= N; i++) {
fa[i] = i;
}
for (register int i = 1; i <= M; i++) {
cin >> edge[i].u >> edge[i].v >> edge[i].w;
}
kruskal();
// 通过边和点的关系判断是否完成连通
if (cnt != N - 1) puts("orz");
else printf("%d", ans);
return 0;
}