- 最小生成树的概念
对于一个顶点集为V,边集为E的无向图来说,生成树成树为:
由 V 中的全部 n 个顶点和 E 中 n−1 条边构成的无向连通子图被称为 G 的一棵生成树,其中边的权值之和最小的生成树被称为无向图 G 的最小生成树。
大白话:就是找n-1条边恰好连接n个节点,这个东西就是生成树,n-1条边的权重最小值,就是最小生成树的代价。
- Kuskal算法
- 将边按照权重由小到大排序
- 遍历每一条边,如果这个这个边连接的两个顶点不连通,将这条边加入答案。
思想就是贪心算法。时间复杂度取决于排序的时间,快排
0
(
m
l
o
g
m
)
0(mlogm)
0(mlogm)
其中
m
=
∣
E
∣
m=|E|
m=∣E∣
- 代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e5+5;
struct Edge{
int a, b, w;
bool operator < (const Edge &O) const {
return w < O.w;
}
}edges[MAXN];
int par[MAXN];
int find(int a) {
if (par[a] == a) return a;
return par[a] = find(par[a]);
}
int main() {
int m, n;
cin >> n >> m;
for (int i = 0; i < m; i++) {
cin >> edges[i].a >> edges[i].b >> edges[i].w;
}
sort(edges, edges + m);
for (int i = 1; i <= n; i++) {
par[i] = i;
}
int cnt = 0, spent = 0;
for (int i = 0; i < m; i++) {
int a = find(edges[i].a);
int b = find(edges[i].b);
if (a != b) {
par[a] = b;
spent += edges[i].w;
cnt ++;
}
}
if (cnt != n - 1) printf("impossible\n");
else printf("%d\n", spent);
}
4.注意点
- 代码使用了并查集来判断两个顶点是否连通,并查集的par初始化一定要注意。
- 可以不适用临界表保存边,直接写一个重载的结构体就行了。
对于typedef struct和struct的区别看这里。 - cnt保存了最小生成树边集的数目,如果需要输出可以使用数组保存边。
- 例题
- leecode 1584 模板题目