最小生成树
\(Prim\)
思路
类似于\(dijkstra\),每次从当前已选过的点中连边选出最优的一个添加,并把该点加入集合。时间复杂度为\(O(n^2)\)。可以进行堆优化,但优化后时间复杂度仍与\(kruskal\)相当且代码复杂,适用于稠密图。
\(Code\)
int Prim(){
memset(dist, 0x3f3f3f3f, sizeof(dist));
int res = 0;
for(int i = 1; i <= n; i++){
int w = -1;
for(int j = 1; j <= n; j++)
if(!vis[j] && (w == -1 || dist[j] < dist[w]))
w = j;
if(i != 1 && dist[w] == INF) return INF;
if(i != 1) res += dist[w];
for(int j = 1; j <= n; j++)
dist[j] = min(dist[j], g[w][j]);
vis[w] = true;
}
return res;
}
\(Kruskal\)
思路
基于对边的排序,对边从小到大排序后,每次判断两点是否已经有连通,每次判断最短的边添加,用并查集查询是否能添加。时间复杂度为\(O(e\log e)\)。
\(Code\)
int find(int x){
if(fa[x] != x)
fa[x] = find(fa[x]);
return fa[x];
}
int kruskal(){
sort(e+1, e+m+1, cmp);
for(int i = 1; i <= n; i++) fa[i] = i;
int res = 0, cnt = 0;
for(int i = 1; i <= m; i++){
int a = e[i].a, b = e[i].b, w = e[i].w;
a = find(a), b = find(b);
if(a != b){
fa[a] = b;
res += w;
cnt++;
}
}
if(cnt < n - 1) return INF;
return res;
}