算法 | Kruskal 算法
求最小生成树(适合稀疏图):Kruskal (克鲁斯卡尔) 算法
- 最小生成树是一副连通加权无向图中一棵权值最小的生成树。
Kruskal 算法
时间复杂度
时间复杂度:
代码实现
const int MAXN = 1e5 + 10, INF = 0x3f3f3f3f;
int v, e; // v顶点数 e边数
int fa[MAXN]; // 并查集
struct Edge // 边的结构体,重载了<供sort()
{
int start, end, dist;
bool operator<(const Edge &x) const
{
return dist < x.dist;
}
};
vector<Edge> edges; // 邻接表存边
inline void init(int n)
{
for (int i = 1; i <= n; i++)
fa[i] = i;
}
int find(int x)
{
return x == fa[x] ? x : (fa[x] = find(fa[x]));
}
inline void merge(int i, int j)
{
fa[find(i)] = find(j);
}
int kruskal()
{
sort(edges.begin(), edges.end());
int ans = 0, selected = 0;
bool flag = false;
for (auto ed : edges)
{
if (find(ed.start) != find(ed.end))
{
merge(ed.start, ed.end);
ans += ed.dist;
if (++selected == v - 1)
{
flag = true;
break;
}
}
}
return flag ? ans : INF;
}
分析
该算法的核心思想就是:选择
实现“选择
实现“权值最小”的方法:将边储存在 vector
内,按长度排序(我用的重载运算符和 sort()
)
实现“不会成环”的方法:判断两节点是否已经联通,若已经联通,再加一条边肯定会成环,只有不连通才能合并(我用的并查集)。
下面用例子模拟一下该算法的过程:
初始化并查集:
将每个节点指向自身,图中用不同颜色表示。
找到最短的边
找到最短的边
找到最短的边
找到最短的边
找到最短的边
这时已经求出了最小生成树,后续操作均会成环,因此都会被跳过。
本文采用 CC BY-SA 4.0 许可,本文 Markdown 源码:Haotian-BiJi