kruskal算法

点击查看代码
#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; //否则返回最小生成树的边权之和
}

posted @ 2022-09-30 22:51  zhaoo_o  阅读(35)  评论(0编辑  收藏  举报