最小生成树之kruskal算法(结构体实现)

(一)Kuskal算法

【算法简介】:上一篇中的Prime算法是一种“加点式的算法”,而Kuskal算法是一种“加边式的算法”;Kuskal算法与Prime算法都是一种贪心算法,但Kruskal算法对图中存在相同权值的边时也有效。
【算法思想】:算法对权值从小到大排序,每次选取当前权值最小的边加入结点,直到所有的结点都已加入结点。算法中用到了并查集的思想(并查集),通过并查集来判断两个结点是否有共同的父节点,如果有,则表明两个结点已经联通。如果没有,就将两个结点联通,记录路径。

1.1 存图方式

使用结构体数组来存图;

struct node
{
	int a;		//边的起点
	int b;		//边的终点
	int p;		//边的权值,即:两结点点之间的距离
}mp[N];		//定义一个结构体数组来存图;

1.2 并查集思想(重点)

分为三部分:
(1)初始化:使每个结点的初始根节点为自己,并且每个结点构成一颗树,树的深度是1;
(2)查找:使用递归来查找每个结点的父亲结点;
(3)合并:将不同父节点的结点合并;
注:这里的并查集是优化后的,即:进行了路径压缩。如果题目中无要求,可以只写简单的并查集算法。

void inin(int n)
{
	int i;
	for (i = 0; i <= n; i++)
	{
		par[i] = i;	//刚开始,每个数的跟节点都是自己
		rank1[i] = 1;		//刚开始树的深度为1;
	}
}
int find(int x)	//找每个结点的父亲结点;
{
	if (x == par[x])
		return x;
	else
	{
		return par[x] = find(par[x]);
	}
}
bool join(int a,int b)	//将两个不同父节点的结点合并
{
	int fa;
	int fb;
	fa = find(a);
	fb = find(b);
	if (fa == fb)
		return false;
	else if (rank1[fa] > rank1[fb])
	{
		par[fb] = fa;
	}
	else
	{
		if (rank1[fa] == rank1[fb])
		{
			rank1[fb]++;
		}
		par[fa] = fb;
	}
	return true;
}

1.3 Kuskal算法主体

变量每个结点;

int kruskal(int m)
{
	int i;
	sort(mp, mp + m, cmp);
	for (i = 0; i < m; i++)
	{
		if (find(mp[i].a) != find(mp[i].b))//如果两个结点的父亲结点不一样,就合并。
		{
			join(mp[i].a, mp[i].b);
			sum = sum + mp[i].p;
		}
	}
	return sum;
}

Kuskal算法完整代码实现:

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 1000
int par[N];	//记录父亲结点
int rank1[N];	//树的深度;
int sum;		//最短路径
struct node
{
	int a;		//边的起点
	int b;		//边的终点
	int p;		//边的权值,即:两结点点之间的距离
}mp[N];		//定义一个结构体数组来存图;
bool cmp(node a,node b)
{
	return a.p < b.p;
}	//对边的权值进行从小到大排序
void inin(int n)
{
	int i;
	for (i = 0; i <= n; i++)
	{
		par[i] = i;	//刚开始,每个数的跟节点都是自己
		rank1[i] = 1;		//刚开始树的深度为1;
	}
}
int find(int x)	//找每个结点的父亲结点;
{
	if (x == par[x])
		return x;
	else
	{
		return par[x] = find(par[x]);
	}
}
bool join(int a,int b)	//将两个不同父节点的结点合并
{
	int fa;
	int fb;
	fa = find(a);
	fb = find(b);
	if (fa == fb)
		return false;
	else if (rank1[fa] > rank1[fb])
	{
		par[fb] = fa;
	}
	else
	{
		if (rank1[fa] == rank1[fb])
		{
			rank1[fb]++;
		}
		par[fa] = fb;
	}
	return true;
}
int kruskal(int m)
{
	int i;
	sort(mp, mp + m, cmp);
	for (i = 0; i < m; i++)
	{
		if (find(mp[i].a) != find(mp[i].b))//如果两个结点的父亲结点不一样,就合并。
		{
			join(mp[i].a, mp[i].b);
			sum = sum + mp[i].p;
		}
	}
	return sum;
}
int main()
{
	int n, m;
	cin >> n>>m;
	inin(m);
	int i;
	for (i = 0; i < m; i++)
	{
		cin >> mp[i].a >> mp[i].b >> mp[i].p;
	}
	sum = 0;
	kruskal(m);
	cout << sum << endl;
	return 0;
}

输入样例1:5个点,8条边,

5 8
1 2 3
1 3 7
2 3 10
2 4 4
2 5 8
3 4 6
3 5 2
4 5 17

输出:

输入样例2:9个点,14条边,

9 14
1 2 4
2 3 8
3 4 7
4 5 9
5 6 10
6 7 2
7 8 1
8 9 7
2 8 11
3 9 2
7 9 6
3 6 4
4 6 14
1 8 8

输出:37

在这里插入图片描述

发布了59 篇原创文章 · 获赞 47 · 访问量 5520

猜你喜欢

转载自blog.csdn.net/qq_44755403/article/details/90384906