最小生成树-kruskal

kruskal算法

将一个连通图的边全部删除,剩下一个个顶点。通过选择最短路径连接对应的顶点,直至构成一棵生成树,则这棵生成树一定是最小生成树。Kruskal算法就是通过此方法来建立一棵最小生成树的。其通过不断添加边的过程构成最小生成树。区别于Kruskal算法,Prim算法则是通过添加点来构造最小生成树。

构造过程:
  1. 保存各顶点间边的连通情况及其对应权值,按对应权值排序(选择最短路径/最小权值连接对应顶点)
  2. 将连通图划分成一个个单一顶点(删除全部边)
  3. 选择最短路径(最小权值),将边添加到相应的两个顶点间
  4. 生成树中是没有回路的,则重构过程如何避免回路?分析发现,如果选中边的对应顶点的连通域相同,则一定会产生回路,因此这样的两个顶点不能连接
  5. 直至所有顶点在同一个连通域中,否则重复步骤3
    在这里插入图片描述
    关于步骤四的分析:

在这里插入图片描述
如上图,因为边权值1、2、3、4最小,所以优先连接相应的边。当权值取5时,发现顶点1和4可以连接,顶点3和4可以连接,顶点2和3也可以连接。倘若连接顶点1和4,则顶点3、4、6构成回路(不是生成树)。这时候我们则可以通过连通域来判断选择哪条边。当顶点1和3连接时构成连通域1,顶点4和6连接时构成连通域4,顶点3和6连接,此时连通域不同(一个是1,一个是4。1,4可以随便选择,这里只是为了区别不同的连通域)因此可以连接,连接后构成了一个大的连通域,我们不妨称其为连通域1。倘若选择顶点3和4连接,但它们属于同一连通域,则会产生回路,因此选择下一条边。当选择顶点1和4时,同样属于一个连通域也不能选择,则再选择下一条边。即连通域相同的两个顶点不能相互连接。

算法步骤:
  1. 如构造过程步骤1,需要存储连通图中边的关系(起始顶点,终止顶点,权值),因此我们声明一个结构体保存
  2. 单一顶点(每一个顶点即一个连通域,连通域内仅自己)可以用一维数组存储,表示顶点所属的连通域
  3. 按连通图中边的权重大小排序(升序)
  4. 选择权值最小的边,查看其相应的顶点所属连通域是否相同,如果相同则不能连接(产生回路),否则连接相应的边(记录相应的权值)
  5. 直至所有顶点在同一个连通域中,否则重复步骤4
代码示例:
#include<iostream>
#include<algorithm> 
using namespace std;

#define MAX_SIZE 100
struct Edge{
 	int h, t;
 	int w;
};

int con[MAX_SIZE];
Edge edge[MAX_SIZE];

bool cmp(Edge x, Edge y){
 	return x.w < y.w;
}
void init_graph(int m){
 	for(int i = 0; i < m; i++){
  		cin >> edge[i].h >> edge[i].t >> edge[i].w;
 	}
}
int kruskal(int n, int m){
 	int sum = 0;
 	sort(edge, edge+m, cmp);
 	for(int i = 1; i <= n; i++){//表示每个顶点都是单一顶点,无连通 
  		con[i] = i;
 	}
 	for(int i = 0; i < m; i++){
  		int h = con[edge[i].h];
  		int t = con[edge[i].t];
  		if(h != t){
   			cout << edge[i].h << " " << edge[i].t << endl;
   			sum += edge[i].w;
   			for(int j = 1; j <= n; j++){
    				if(con[j] == t){
     					con[j] = h;
    				}
   			}
 		}
 	}
 	return sum;
}

int main(){
 	int n, m;
 	cin >> n >> m;
 	init_graph(m);
 	cout << kruskal(n, m);
 	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值