Appearance
简介
无向图
对于
图
最小生成树,即边权和最小的生成树。
Kruskal 算法
Kruskal 是一种贪心算法。
- 将
条边按照边权升序排序; - 从小到大枚举边:
- 若此边的两个顶点未连通,则在树中加入此边,并连通两个顶点;
- 若此边的两个顶点已连通,直接跳到下一条边。
- 重复直到树中共加入
条边。
使用 并查集 判断和维护两个顶点是否连通。
时间复杂度为
cpp
const int N = 1e6;
int n, m, fa[N];
struct edge { int x, y, len; } g[N];
bool cmp(edge x, edge y) {
return x.len < y.len;
}
int find(int x) {
return !fa[x] ? x : fa[x] = find(fa[x]);
}
int kruskal() {
sort(g + 1, g + m + 1, cmp);
int tot = 0, sum = 0;
for (int i = 1; i <= m; i ++) {
if (tot == n - 1) break;
int rx = find(g[i].x);
int ry = find(g[i].y);
if (rx != ry) {
tot ++, fa[rx] = ry, sum += g[i].len;
}
}
// 如果存在最小生成树,则返回边权和,否则返回 -1
return tot == n - 1 ? sum : -1;
}
Prim 算法
和 Dijkstra 算法非常类似。
- 建立一棵只有
号节点的树, ; - 选择离树最近(
最小)的节点加入树,对该点的所有临边进行 松弛操作。重复执行直到加入 条边。
时间复杂度为
cpp
int prim() {
int sum = 0;
memset(avl, true, sizeof avl);
memset(dis, 0x7f, sizeof dis);
dis[1] = 0;
for (int i = 2; i <= n; i ++) {
int minn = INF, minp = 0;
for (int j = 2; j <= n; j ++)
if(avl[j] && dis[j] < minn)
minn = dis[j], minp = j;
if (!minp) return -1;
avl[minp] = false, sum += minn;
for (int j = 1; j <= n; j ++)
if (avl[j] && dis[j] > g[minp][j])
dis[j] = g[minp][j];
}
return sum;
}