Kruskal算法
Kruskal算法是求最小生成树的一种算法,运用了贪心的思想,十分常用。算法流程大体如下:将m条边按边权从小到大排序,枚举每条边,如果该边的起点和终点已经在最小生成树中,则跳过,否则就将这条边加入到最小生成树中。具体实现方面会借助于并查集,来判断两个点是否在最小生成树中(已连通)。
1 #include <cstdio> 2 #include <algorithm> 3 4 using namespace std; 5 6 struct Edge { 7 int u, v, w; 8 bool operator < (const Edge& rhs) const { 9 return w < rhs.w; 10 } //规定边的优先级用于排序 11 } edge[maxm]; 12 13 int n, m, fa[maxn]; 14 15 int dj_find(int i) { 16 if (i == fa[i]) return i; 17 else return fa[i] = dj_find(fa[i]); 18 } 19 20 inline void dj_merge(int a, int b) { 21 a = dj_find(a), b = dj_find(b); 22 if (a != b) fa[a] = b; 23 } //定义并查集的查询合并操作 24 25 inline int Kruskal() { 26 int cnt = 0, sum = 0; 27 for (int i = 1; i <= n; ++i) fa[i] = i; 28 sort(edge + 1, edge + m + 1); //按边权排序 29 for (int i = 1; i <= m; ++i) { 30 int u = edge[i].u, v = edge[i].v; 31 if (dj_find(u) != dj_find(v)) { 32 dj_merge(u, v); 33 sum += edge[i].w; 34 ++cnt; 35 } //若边的起点和终点之前未连通,则连通 36 if (cnt == n - 1) return sum; 37 } //最小生成树有n-1条边 38 return -1; 39 }
呃呃,附上一道裸题,USACO习题最短网络,在洛谷上的链接为:https://www.luogu.org/problemnew/show/P1546