图论最小生成树-Kruskal算法

Kruskal是用于求出加权无向图的最小生成树的算法。核心思想:按照权值从小到大选边且不会形成环状,直到选完n-1条边(n为结点数)

最小生成树:对于无向加权图来讲,就是包含图中所有顶点的连通子图且边权之和为最小(无环状,边数为n-1)

举个例子:在几个村庄间修路,这条路可以达到每一个村庄且花费最少(权值之和最小)

给出一个连通图

 首先我们将他们按照权值排序:

(0,5)权值:10        (2,3)权值:12        (1,6)权值:14        (1,2)权值:16

(3,6)权值:18        (3,4)权值:22        (4,6)权值:24        (4,5)权值:25

从小到大选边且不为环状

(0,5)没有成环,作为第一条边,此时

(2,3)没有成环,作为第二条边,此时

(1,6)没有成环,作为第三条边

(1,2)没有成环,作为第四条边

(3,6)发现已选边已经成环状,所以不选

(0,1)没有成环,作为第五条边

(3,4)没有成环,选择作为第六条边

已经选完n-1条边,且不成环状,选边结束

结果如下

 代码如下:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAX_SIZE=100;
struct Edge {
	int u;  //起始点
	int v;  //终止点
	int w;  //权值
};
Edge e[MAX_SIZE];   //存放图的边集的结构体数组
void addedge(int n, int u, int v, int w) {   //用于添加边集
	e[n].u = u;
	e[n].v = v;
	e[n].w = w;
}
int parent[10]; //并查集数组,存储每个节点的父节点,用于判断连通性
bool compare(Edge a, Edge b) {    //用于sort函数按照权值排序
	return a.w < b.w;
}
int find(int x) {                 //用于查找x的根节点
	if (parent[x] == x) { return x; }  //结束条件:直到索引==根节点的值
	else {
		find(parent[x]);           //传入x的父节点到find
	}
}
void uniontree(int a, int b) {     //用于将a,b放入同一个并查集中
	a = find(a);
	b = find(b);
	if (a != b) {
		parent[b] = a;
	}
}

void kruskal(int n) {
	for (int i = 0;i < n;i++) {    //初始化并查集,他们的根节点为本身
		parent[i] = i;
	}
	int count = 1;                //已选边数
	int i = 0;
	while (count < n) {           //一共要找n-1条边
		int u = e[i].u;
		int v = e[i].v;
		int w = e[i].w;
		if (find(u) != find(v)) {   //判断两个结点是否属于同一个树
			uniontree(u, v);        //合并两个树
			count++;                //找到的边数+1
			printf("(%d,%d),权值:%d\n", u, v, w);
		}
		i++;
	}
}
int main() {
	addedge(0, 0, 1, 20);
	addedge(1, 0, 5, 10);
	addedge(2, 1, 2, 16);
	addedge(3, 1, 6, 14);
	addedge(4, 2, 3, 12);
	addedge(5, 3, 4, 22);
	addedge(6, 3, 6, 18);
	addedge(7, 4, 5, 25);
	addedge(8, 4, 6, 24);
	sort(e, e + 9, compare);   //按照权值进行升序排序;
	kruskal(7);  //一共7个结点
}

总结:Kruskal核心就是将所有边按照权值升序排序,从小到大选择边且不成环状,直到选完n-1条边为止。

此篇文章用于给总结巩固知识点,如果帮助到大家也是非常荣幸,如果文章有错误,感谢批评和指出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值