最小生成树——克鲁斯卡尔(Kruskal)算法

前面说的普利姆算法是以某顶点为起点,逐步找各顶点上最小权值的边,来构建最小生成树的。这就像是我们如果去参观某个展会,一种方法是从入口进去后,到最近的场馆观光,看完后再紧挨着看下一个;还有例外一个方法,实现计划好所有路线,进展会后直接去最想看的场馆,也就相当于去之前做好了攻略。

直接找最小权值的边来构建最小生成树,只不过每次构建是要考虑是否形成环路。

同样是这个题:假如你是一位工程师,需要为一个镇的九个村庄架设通信网络做设计,村庄位置大值如下图:

 其中 V0~V8 是村庄,之间连线的数字表示村与村间的可通达的直线距离,比如 V0 至 V1 就是 10 千米(个别如 V0 与 V6,V6 与 V8,V5 与 V7 为测算距离是因为有高山或者湖泊,不予考虑)。你们领导要求你必须用最小的成本完成本次任务。该怎么做?

样例输入

9 15
0 1 10
0 5 11
1 6 16
6 5 17
1 2 18
1 8 12
2 8 8
2 3 22
3 8 21
3 6 24
6 7 19
3 7 16
3 4 20
4 5 26
4 7 7

样例输出

(4,7) 7
(2,8) 8
(0,1) 10
(0,5) 11
(1,8) 12
(1,6) 16
(3,7) 16
(6,7) 19

解题思路

同样的要用一个方法存储输入的信息, Prim 算法是用的二维邻接矩阵存储,而 Kruskal 算法是用结构体存储,分别用 begin、end、weight 代表存入的一组数据。

因为每次都要找最小的权值,找到后删除该数,再找最小权值。这样的话 ,可以在进入 MiniSpanTree_Kruskal 函数之前就排好序,如图所示(按权值从小到大排序)。

 然后主要是通过 Find 函数判断两点之间是否已经连通,Find 函数代码:

int Find(int parent[],int f)
{
	while(parent[f]>0)//循环直至以当前点为下标的点为 0,此时没有其余连接的点(如果在同一颗生成树中,通过 Find函数可以实现从不同分支可以到达同一个点) 
	f=parent[f];
	return f;
}

然后解决了权值的排序问题和生成树出现环路的问题之后,代码就好理解了。

代码如下:

#include<stdio.h>
int n,m;
//用结构体存储输入的信息 
struct node
{
	int begin;
	int end;
	int weight;//权值 
};
struct node k[1000],t;
//用来找两者共同到达的点,相同的话就已经在生成树里面了,不相同的话就没有在生成树中 
int Find(int parent[],int f)//并查集
{
	while(parent[f]>0)//循环直至以当前点为下标的点为 0,此时没有其余连接的点(如果在同一颗生成树中,通过 Find函数可以实现从不同分支可以到达同一个点) 
	f=parent[f];
	return f;
}
void MiniSpanTree_Kruskal()
{
	int i,d,b;
	int parent[1000]; 
	for(i=0;i<n;i++)
	{
		parent[i]=0;//把数组初始化为 0, 
	}
	for(i=0;i<m;i++)
	{
		d=Find(parent,k[i].begin);//找 k[i].begin对应的值 
		b=Find(parent,k[i].end);//找 k[i].end对应的值 
		if(d!=b)//不相等的话说明连接起来不会形成回路 
		{
			parent[d]=b;//通过这个步骤,说明两点已经连接起来 
			printf("(%d,%d) %d\n",k[i].begin,k[i].end,k[i].weight);
		}
	}
}
int main()
{
	int i,j;
	scanf("%d %d",&n,&m);
	for(i=0;i<m;i++)
	scanf("%d %d %d",&k[i].begin,&k[i].end,&k[i].weight);
	for(i=0;i<m-1;i++)//冒泡排序 
	{
		for(j=0;j<m-i-1;j++)
		{
			if(k[j].weight>k[j+1].weight)
			{
				t=k[j];//提前定义好结构体变量 t(注意这里不要写成 k[j].weight) 
				k[j]=k[j+1];
				k[j+1]=t;
			}
		}
	}
	MiniSpanTree_Kruskal();
}

总结

prim 算法适用于边稠密的情况;它是从某一顶点开始构建树,直至所有顶点都进入生成树;顶点数为 n,时间复杂度为 O(n^{2});

Kruskal 算法适用于边稀疏的情况;它是从某一边开始构建树,直至所有顶点都连通;边长数为 e,时间复杂度为 O( e log e)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明里灰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值