Prim算法
适用场景
时间复杂度为 O ( n 2 ) O(n^2) O(n2),适用于稠密图,按照邻接矩阵存储。
思路
总体思路于dijkstra算法类似,dijkstra算法每次找离原点最近的点,而prim算法每次找离集合最近的点,如果没学dijkstra的话建议先去学习一下,过程也与dijkstra算法类似,这里直接写模版了。
模版
int g[maxn][maxn]; //邻接矩阵
int dist[maxn]; //到最小生成树的最短距离
bool st[maxn]; //是否在最小生成树集合中
int prim(){
memset(dist, 0x3f, sizeof dist);
int res = 0; //最小生成树路径总和
for (int i = 0; i < n; i ++){ //找最小生成树遍历n次,没有初始化第一个点
int t = -1;
for (int j = 1; j <= n; j ++){ //找到当前离集合最近的点
if (!st[j] && (t == -1 || dist[t] > dist[j])) t = j;
}
if (i && dist[t] == INF) return -1; //最近的点都是无穷表示不联通
if (i) res += dist[t]; //加上路径
st[t] = true;
for (int j = 1; j <= n; j ++){
dist[j] = min(dist[j], g[t][j]);//直接用距离更新
}
}
return res;
}
Kruskal算法
适用场景
稀疏图,时间复杂度 O ( m l o g m ) O(mlogm) O(mlogm),m为边的数量,直接存边即可
思路
思路也比较好理解,需要一些并查集的前置知识。首先存好边,之后按照边的权重大小从小到大拍好序,从小到大连边,当连接的边在一个联通块中时,跳过该边,不在联通块时加入该边,当一共加入n-1条边时,就是一个最小生成树。
模版
int fa[maxn];
struct Edge{
int u, v, w;
}edges[maxn * maxn];
bool cmp(Edge a, Edge b){retrun a.w < b.w;}
//-----------并查集模版--------------
void ini(){
for (int i = 1; i <= n; i ++) fa[i] = i;
}
int find(int x){
return x == fa[x] ? x : (fa[x] = find(fa[x]));
}
void add(int a, int b){
int x = find(a), y = find(b);
if (x != y) fa[x] = y;
}
//-----------------------------------
int kruskal(){
ini();
sort(edges, edges + m, cmp); //从小到大排序边
int cnt = 0; //计数加入了多少条边
int res = 0; //记录结果
for (int i = 0; i < m; i ++){
int U = edges[i].u, V = edges[i].v;
if (find(U) != find(V)){ //如果不在一个联通块
add(U, V);
cnt ++;
res += edges[i].w;
}
if (cnt == n - 1){
return res;
}
}
}