最小生成树算法-prim和kruskal

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;
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值