生成树

本文介绍了生成树的概念,即在给定的无向图中找到一个包含所有顶点的无环联通子图。重点讨论了两种找到最小生成树的方法:Kruskal算法和Prim算法。Kruskal算法通过选择最小边并利用并查集避免形成环,而Prim算法则从一个节点开始逐步扩展最小生成树。这两种算法分别适用于不同的图类型,Kruskal适合稀疏图,Prim更适合稠密图。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

生成树

生成树,好长时间没有学习,居然快忘了什么是生成树了
给定一张边带权的无向图G,由n个顶点和n-1条边构成的无向联通子图叫做一个生成树,边的权值之和最小的生成树叫做最小生成树
也就是说如何选出来n-1条边来链接n个点直到连通

kruskal

既然说了是最小的,那么自然地想起来首先选择当前最小的边,然后直至选择了n-1条边为止,而且这两个端点属于两个不同的树(集合)也就是不联通,那把就把他们加一块,具体的步骤如下:
1.建立一个并查集,每一个点自己独立一个集合
2.把所有边按照权值从小到达的排序,以便我们选择最小的边,依次地扫描每一条边
3.如何这两个点连通(属于同一个集合),那么就跳过这一条边
4.不然,合并两个所在的集合,并且加上这个答案,所有边扫描完成之后,第4步处理过的边就是一个最小生成树
这个算法类似于贪心,用的是排序加上并查集

int get(int x)
{//获取元素代表
	if(x==fa[x]) return x;
	return fa[x]=get(fa[x]);
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
		cin>>e[i].x>>e[i].y>>e[i].z;
	sort(e+1,e+1+m);
	for(int i=1;i<=n;i++)
	{
		fa[i]=i;//独立的集合
	}
	for(int i=1;i<=m;i++)
	{
		int x=get(e[i].x);
		int y=get(e[i].y);
		if(x==y) continue;
		fa[x]=y;//合并
		ans+=e[i].z;
	}
}

Prim

Prim算法的思路稍稍有些改变,维护最小生成树的一部分,他只能确定1号节点属于的最小生成树,有点类似于求单源最短路经
可以类比dijkstra算法,每次从未标记的节点中选出的d值最小的标记一下然后扫描一下所有的出边,更新另一个点的值,主要用于稠密图,尤其是完全图

void prim()
{
	memset(d,0x3f,sizeof(d));
	memsmet(V,0,sizeof(v));
	d[1]=0;
	for(int i=1;i<n;i++)
	{
		int x=0;
		for(int j=1;j<=n;j++)
			if(v[j]==0&&(x==0||d[j]<d[x]))x=j;
		v[x]=1;
		for(int y=1;y<=n;y++)
			if(v[y]==0) d[y]=min(d[y],a[x][y]);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值