最小生成树:
在一给定的连通无向图G = (V, E)中,(u, v)
代表连接顶点u与顶点v的边,而
w(u, v)代表此边的权重,若存在T为G的子集且为无循环图,使得w(T)
最小,则此T为G的最小生成树。
基本思路:
kruskal算法总共选择n- 1条边,所使用的贪婪准则是:从剩下的边中选择一条不会产生环路的具有最小耗费的边加入已选择的边的集合中。注意到所选取的边若产生环路则不可能形成一棵生成树。kruskal算法分e
步,其中e
是网络中边的数目。按耗费递增的顺序来考虑这e
条边,每次考虑一条边。当考虑某条边时,若将其加入到已选边的集合中会出现环路,则将其抛弃,否则,将它选入。
概括如下:
1. 对G的边按权重非降序排列。
2. 一次取权重最小的边,如果把它放入T不会形成回路的话,则把它放入T中,否则将它丢弃。
判断是否形成回路用并查集。
伪代码:
算法分析:
主要耗费在边的排序,时间复杂度为O(mlogm)。
C++代码:
struct edge { int u, v, c; bool operator < (const edge &b) const { return c < b.c; } }e[mxe]; int n, m; int fa[mnx]; int find(int x) { if(fa[x] != x) fa[x] = find(fa[x]); return fa[x]; } // kruskal 复杂度O(|E|log|E|), |E|:边数 int kruskal() { sort(e + 1, e + m + 1); // 边排序 for(int i = 1; i <= n; ++i) fa[i] = i; //并查集初始化 int ret = 0; for(int i = 1; i <= m; ++i) { int u = e[i].u, v = e[i].v, c = e[i].c; u = find(u), v = find(v); if(u != v) { //不在同一个集合里面,则把这一条边加入成为最小生成树的一部分 ret += c; fa[u] = v; } } return ret; }
时间: 2024-10-15 09:42:30