2月1日自习

最小生成树之kruskal算法

最小生成树:将一个带权值的有n个点的无向图只用n-1个边将所有点都连接起来但不形成回路,当这n-1个边所有的权值相加起来最小时,这个n个点和n-1个边形成的图就是最小生成树

从策略上来说,Prim算法是直接查找,多次寻找邻边的权重最小值,而Kruskal是需要先对权重排

序后查找的~

所以说,Kruskal在算法效率上是比Prim快的,因为Kruskal只需一次对权重的排序就能找到最小生

成树,而Prim算法需要多次对邻边排序才能找到~

prim:该算法的时间复杂度为O(n2)。与图中边数无关,该算法适合于稠密图。

kruskal:需要对图的边进行访问,所以克鲁斯卡尔算法的时间复杂度只和边又关系,可以证明其时

间复杂度为O(eloge)。适合稀疏图

Kruskal算法和Prim算法其实都是基于贪心,不过Kruskal算法需要先对边的权值排序,而Prim算法

是每次都选取当前权值最小的边

 

kruskal算法:

原理:简单的贪心算法

大致实现过程:

首先我们把所有的边按照权值先从小到大排列,接着按照顺序选取每条边,如果这条边的两个端点不属于同一集合,且将这两条端点连接上之后在无向图中不会构成环,那么就将这条边纳入最短生成树,直到所有的边都被选完,最小生成树即形成

如何判断两个端点不属于同一个集合?

可以使用深度搜索,但效率过慢,改用并查集

只要一条边的两个端点不属于同一集合,将这条边连接起来就不会在无向图中形成环

 代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define size 10001
struct edge { //边的结构体
	int u;
	int v;
	int w;//u,v分别为该条边的两个顶点,w为该条边的权值
} bian[size];
int n, m;//点和边
int connect[size];
void init() {//并查集初始化
	for (int i = 1; i <= n; i++) {
		connect[i] = i;
	}
}
int find(int x) {//查找端点属于的集合
	return connect[x] == x ? x : connect[x] = find(connect[x]);
}
void unions(int a, int b) {//将两个端点形成的边连接起来
	connect[find(b)] = find(a);
}
int cmp(const void*p1, const void *p2) { //给结构体排序的函数
	return ((struct edge *)p1)->w - ((struct edge *)p2)->w;
}
int main() {
	scanf("%d %d", &n, &m);
	for (int i = 0; i < m; i++) {
		scanf("%d %d %d", &bian[i].u, &bian[i].v, &bian[i].w);
	}
	init();
	qsort(bian, m, sizeof(struct edge), cmp);//根据边的权值排序
	int count = 0; //统计连入多少条边
	int length = 0; //最小生成树长度
	for (int i = 0; i < m && count < n - 1; i++) { //从小到大枚举每一条边
		if (find(bian[i].u) != find(bian[i].v)) { //这条边没有连接起来,两个端点不属于同一集合,即该边没有并入最小树
			unions(bian[i].u, bian[i].v);//将这条边连接起来
			length += bian[i].w;
			count++;
		}
	}
	printf("%d",length);
}

经典例题:洛谷 P2121 拆地毯

题解链接:http://t.csdn.cn/WDB40

另外有两个用prim算法写的题:

洛谷 P2872 Building Roads S

题解链接:http://t.csdn.cn/0ZqDX

 洛谷 P1991 无线通信网

题解链接: http://t.csdn.cn/QXDIG

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值