点击查看代码
#include<cstdio>
#include<algorithm>
#pragma warning(disable:4996)
using namespace std;
//kruskal算法伪代码
int kruskal() {
设最小生成树的边权之和为ans、最小生成树的当前边数Num_Edge;
将所有边按边权从小到大排序;
for (从小到大枚举所有边) {
if (当前测试边的两个端点不在同一个连通块中) {
将该测试边加进最小生成树中;
ans += 测试边的边权;
最小生成树的当前边数Num_Edge加一;
当Num_Edge等于顶点数减一时结束循环;(因为最小生成树的顶点数等于边数加一)
}
}
return ans; //返回最小生成树的边权之和
}
const int maxn = 210; //最多不超过200个顶点
const int INF = 0x3fffffff; //表示无穷大
struct edge {
int u, v; //边的两个端点编号
int cost; //边权
}E[maxn]; //存储图中边的信息,最多有maxn条边
bool cmp(edge a, edge b) { //对图G中的边按边权递增排序
return a.cost < b.cost;
}
//并查集,检查测试边的两个端点是否在同一个连通块(集合)中,
//如果不是,则测试边符合要求,将两个端点合并为一个集合,等价于将测试边加进最小生成树中
int father[maxn]; //并查集数组,存储每个顶点的父顶点编号
int findFather(int x) { //并查集查询函数
int a = x;
while (x != father[x]) {
x = father[x];
}
//路径压缩
while (a != father[a]) {
int z = a;
a = father[a];
father[z] = x;
}
return x;
}
//kruskal算法,函数返回最小生成树的边权之和。图G的顶点数为n,边数为m
int kruskal(int n, int m) {
int ans = 0, Num_Edge = 0; //边权之和,最小生成树当前的边数
for (int i = 0; i < n; i++) { //顶点编号从0~n-1
father[i] = i; //设置每个顶点的父顶点都是自己
}
sort(E, E + m, cmp); //对图中的边按边权递增排序
for (int i = 0; i < m; i++) { //枚举所有边,因为已经对边权按递增排序,所以按边权从小到大选择测试边
int faU = findFather(E[i].u); //查找测试边i的端点u所在集合的父顶点
int faV = findFather(E[i].v); //查找测试边i的端点v所在集合的父顶点
if (faU != faV) { //如果u和v不在同一个集合(连通块)内,则测试边符合要求
father[faU] = faV; //将u和v合并为一个集合(将测试边加进最小生成树中)
ans += E[i].cost; //累加边权之和
Num_Edge++; //当前生成树的边数加一
if (Num_Edge == n - 1) break; //当边数等于顶点数减一时,最小生成树构造完成,结束算法
}
}
if (Num_Edge != n - 1) return -1; //如果测试边全部检查完后生成树的边数不等于顶点数减一,则不能构造出最小生成树,返回-1表示无解
else return ans; //否则返回最小生成树的边权之和
}