克鲁斯卡尔算法手写

本文通过一个C++程序实例介绍了边集数组在实现克鲁斯卡尔算法中的应用,讲解了如何构建最小生成树。程序首先读取图的边信息,使用边集数组存储,然后利用排序和辅助数组判断避免形成回路,逐步构造最小生成树。克鲁斯卡尔算法的关键在于贪心策略,每次都选择当前未加入树的最小边,最终得到的树是权值最小的。文章旨在理解边集数组的概念及其在解决图论问题中的作用。
摘要由CSDN通过智能技术生成

首先,写这个算法是为了了解“边集数组”的实战场景,而边集数组又是图的一种存储方式。
图大致分为下面几种表示方式,每种方式都有其应用场景:
1.邻接矩阵
2.邻接表
3.边集数组
4.链式前向星。
这四个方法后面记得整理一次,现在先记录克鲁斯卡尔算法(用到边集数组)
在这里插入图片描述

测试数据:
7 11
1 2 7
1 4 5
2 4 9
2 3 8
2 5 7
4 5 15
4 6 6
6 7 11
5 6 8
5 7 9
3 5 5

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;


const int maxn =1e5;

struct edge    //边的数据类型
{
	int u;   //一条边的起始
	int v;   //结束
	int w;   //权值,这里可以看作是边的长度
	bool operator <(const edge& a)   //重载<运算符,这一步的目的是对边集合数组排序(排序的依据是权值大小,从小到大排序)
	{
		return w < a.w;
	}
};


edge temp[maxn];    //存放边的数据
int verx[maxn];//辅助数组,判断是否连通。
edge tree[maxn];//最小生成树。
int n, m;//n*n的图,m条边。
int cnt;//统计生成结点个数,若不满足n个,则生成失败。
int sum;//最小生成树权值总和。



void print_tree()    //输出最小生成树
{
	cout << "最小生成树的权值是:" << endl;
	cout << sum << endl;
	for (int i = 0; i < cnt; i++)
	{
		cout << "顶点 " << tree[i].u << " 到顶点 " << tree[i].v << "  的边长是 " << tree[i].w << endl;
	}
}

void Kruskal()   //克鲁斯卡尔
{
	for (int i = 1; i <= n; i++)   //初始化辅助数组
		verx[i] = i;
	sum = 0;
	cnt = 0;
	for (int i = 0; i < m; i++)
	{
		int v1 = verx[temp[i].u];
		int v2 = verx[temp[i].v];
		if (v1 != v2)   //这就是关键,不能形成回路
		{
			//先将这条满足条件的边加入到最小生成树里面
			tree[cnt].u = v1;
			tree[cnt].v = v2;
			tree[cnt].w = temp[i].w;
			//然后要收尾一下,把v1,v2设置为一个连通分量(即下次不会重复找该边)
			for (int i = 1; i <= n; i++)    //这里人为设置,v1,v2都变成v2
				if (verx[i] == v2)verx[i] = v1;
			sum += temp[i].w;
			cnt++;
		}
		
	}
	print_tree();
}

int main()
{
	while (cin >> n >> m)
	{
		int u, v, w;
		for (int i = 0; i < m; i++)
		{
			cin >> u >> v >> w;
			temp[i].u = u, temp[i].v = v, temp[i].w = w;
		}
		sort(temp, temp + m);
		Kruskal();
	}
	return 0;
}



//这个程序的目的在于3点:
//1.知道边集数组的概念,边集数组,就是存储边信息的数组,边的信息,无非就是起点终点,边的长度(也就是权值)
//2.知道克鲁斯卡尔算法的大致过程,即通过一个辅助数组verx,在不形成回路的情况下(v1!=v2),由已经从小到大排序的边里面,挑
//选当前最小的边,然后加入最小生成树,因为每次找到的边都是最小的,所以最后生成的树也是最小的,有点贪心的味道。
//3.结合起来,知道边集数组应用的场合
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值