最小生成树的Kruskal算法和Prim算法

C++最小生成树(kruskal算法,prim算法) 生成树是一种特殊的连通子图,它在保持图中所有顶点的同时,只包含了构成一棵树的边数,即n-1条边,其中n是图中的顶点数量。生成树是无环的,并且是连通的,这意味着通过生成树可以从任何一个顶点到达其他任何顶点,而不需要回溯或形成环路。权值最小的生成树称为最小生成树。 阅读详情

Kruskal算法执行流程:
初始化:图的每一个顶点各自在只有自己组成的连通分量里
执行过程:按从小到大的顺序遍历图的所有边,对于当前边e
如果e的两个端点在同一个连通分量里,忽略e,否则合并
e的两个端点各自所在的连通分量为一个连通分量,并把e加入最小生成树的边集合.当处理的未被忽略的边e的数量达到图的顶点数减1,算法终止

Prim算法的执行流程;
初始化:选择一个顶点v0,把所有顶点划分为两个集合S和T,
v0在S中,剩余顶点在T中,把一端为v0另一端在T中所有边加入集合E
执行过程:从E中选择一条权值最小的跨越S,T的边e,将e加入最小生成树,将e在T中的端点v从T中移出,放入S,并将所有一端为s,另一端在T中的所有边加入E,然后重复迭代,当T为空集时终止算法

Kruskal算法的正确性证明:截取自王树禾图论第二版2.4节定理2.4的证明
在这里插入图片描述
Prim算法正确性证明:截取自算法导论第三版23.1节
在这里插入图片描述
C++实现:

#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
using namespace std;

struct EdgeNode
{
	size_t vertex_id;
	EdgeNode* next = nullptr;
	EdgeNode(size_t& v) :vertex_id(v) {}
};

template <typename T>
struct EdgeInfo
{
	long long u;
	long long v;
	T weight;
	bool operator<(const EdgeInfo& e)
	{
		return weight < e.weight;
	}

	bool operator>(const EdgeInfo& e)
	{
		return e.weight < weight;
	}

	bool operator==(const EdgeInfo& e)
	{
		return !(weight < e.weight) && !(e.weight < weight);
	}

	bool operator<=(const EdgeInfo& e)
	{
		return !(e.weight < weight);
	}

	bool operator>=(const EdgeInfo& e)
	{
		return !(weight < e.weight);
	}
	EdgeInfo() = default;
	EdgeInfo(long long _u, long long _v, const T& _weight) :u(_u), v(_v), weight(_weight) {}
};

class Graph
{
public:
	Graph(const size_t& N) :vertex_list(N, nullptr) {};

	bool insertEdge(size_t u, size_t v)
	{
		if (u != v && u < vertex_list.size() && v < vertex_list.size())
		{
			if (vertex_list[u] == nullptr)
			{
				vertex_list[u] = new EdgeNode(v);
			}
			else
			{
				EdgeNode* t = new EdgeNode(v);
				t->next = vertex_list[u];
				vertex_list[u] = t;
			}

			if (vertex_list[v] == nullptr)
			{
				vertex_list[v] = new EdgeNode(u);
			}
			else
			{
				EdgeNode* t = new EdgeNode(u);
				t->next = vertex_list[v];
				vertex_list[v] = t;
			}
			return true;
		}
		return false;
	}
	size_t getVertexNum() { return vertex_list.size(); }
	EdgeNode* getFirstEdge(size_t u) { return vertex_list[u]; }
	EdgeNode* nextEdge(EdgeNode* cur)
	{
		if (cur == nullptr)
			return nullptr;
		return cur->next;
	}
private:
	vector<EdgeNode*> vertex_list;
};

void edgeNumAndWeightSum(Graph& g, size_t &EdgeNum, int &WeightSum, vector<vector<pair<bool, int>>> &_edge)
{
	EdgeNum = 0;
	WeightSum = 0;
	for (size_t i = 0; i < g.getVertexNum(); ++i)
	{
		for (EdgeNode* run = g.getFirstEdge(i); run != nullptr; run = g.nextEdge(run))
		{
			++EdgeNum;
			WeightSum += _edge[i][run->vertex_id].second;
		}
	}
	EdgeNum /= 2;
	WeightSum /= 2;
}

class UnionFindSet
{
public:
	UnionFindSet(size_t N) :_set(N, -1) {}
	long long findSet(long long n)
	{
		long long p = n;
		while (_set[p] >= 0)
		{
			p = _set[p];
		}

		long long cur = n;
		while (cur != p)
		{
			long long temp = _set[cur];
			_set[cur] = p;
			cur = temp;
		}
		return p;
	}

	void unionSet(long long left, long long right)
	{
		long long left_set = findSet(left);
		long long right_set = findSet(right);
		if (left_set != right_set)
		{
			if (_set[left_set] < _set[right_set])
			{
				_set[left_set] += _set[right_set];
				_set[right_set] = left_set;
			}
			else
			{
				_set[right_set] += _set[left_set];
				_set[left_set] = right_set;
			}
		}
	}
private:
	vector<long long> _set;
};

template <typename T>
class Heap
{
public:
	Heap() = default;
	Heap(const vector<T>& input)
	{
		heap = input;
		for (size_t run = heap.size() / 2; run >= 1; --run)
		{
			updownAdjust(run - 1);
		}
	}
	void insert(const T &key);
	bool removeMinValue(T &key);
	void _clear()
	{
		heap.clear();
	}
private:
	void updownAdjust(size_t top);
	void downupAdjust();
	vector<T> heap;
};

template <typename T>
bool Heap<T>::removeMinValue(T &key)
{
	if (heap.empty())
		return false;
	key = heap[0];
	swap(heap[0], heap.back());
	if (heap.size()>=2)
	  heap.pop_back();
	updownAdjust(0);
	return true;
}

template <typename T>
void Heap<T>::insert(const T& key)
{
	heap.push_back(key);
	downupAdjust();
}

template <typename T>
void Heap<T>::updownAdjust(size_t top)
{
	size_t cur = top + 1;
	size_t temp = 2 * cur;
	T value = heap[top];
	while (temp <= heap.size())
	{
		if (temp < heap.size() && heap[temp-1] > heap[temp])
		{
			++temp;
		}

		if (heap[temp - 1] >= value)
		{
			break;
		}

		heap[cur - 1] = heap[temp - 1];
		cur = temp;
		temp *= 2;
	}
	heap[cur - 1] = value;
}

template <typename T>
void Heap<T>::downupAdjust()
{
	size_t cur = heap.size();
	size_t temp = cur / 2;
	T value = heap.back();

	while (cur > 1)
	{
		if (heap[temp - 1] <= value)
		{
			break;
		}

		heap[cur - 1] = heap[temp - 1];
		cur = temp;
		temp /= 2;
	}
	heap[cur - 1] = value;
}
# define N 6

int main()
{
	vector<EdgeInfo<int>> input{EdgeInfo<int>(0, 1, 6), EdgeInfo<int>(0, 2, 1), EdgeInfo<int>(0, 3, 5), EdgeInfo<int>(1, 2, 5), EdgeInfo<int>(1, 4, 3), EdgeInfo<int>(2, 4, 6), EdgeInfo<int>(2, 3, 5), EdgeInfo<int>(2, 5, 4), EdgeInfo<int>(3, 5, 2), EdgeInfo<int>(4, 5, 6)};
	vector<vector<pair<bool, int>>> EdgeWeightInfo(N, vector<pair<bool, int>>(N, make_pair(false, -1)));
	for (const auto& run : input)
	{
		EdgeWeightInfo[run.u][run.v] = make_pair(true, run.weight);
		EdgeWeightInfo[run.v][run.u] = make_pair(true, run.weight);

	}
	Heap<EdgeInfo<int>> h(input);
	UnionFindSet _set(N);
	Graph g(N);

	for (size_t i = 1; i < N; ++i)
	{
		while (true)
		{
			EdgeInfo<int> temp;
			h.removeMinValue(temp);
			long long left = _set.findSet(temp.u);
			long long right = _set.findSet(temp.v);
			if (left != right)
			{
				g.insertEdge(temp.u, temp.v);
				_set.unionSet(left, right);
				break;
			}
		}
	}

	h._clear();
	vector<vector<pair<bool, int>>> _edge{ {{true, 6}, {true, 1}, {true, 5}, {false, -1}, {false, -1}}, {{true, 5}, {false, -1}, {true, 3}, {false, -1}}, {{true, 5}, {true, 6}, {true, 4}}, {{false, -1}, {true, 2}}, {{true, 6}}};
	vector<bool> in_S_or_in_T{ true, false, false, false, false, false };
	Graph _graph(N);
	for (size_t j = 0; j < _edge[0].size(); ++j)
	{
		if (_edge[0][j].first)
		{
			h.insert(EdgeInfo<int>(0, j+1, _edge[0][j].second));
		}
	}

	for (size_t i = 1; i < N; ++i)
	{
		while (true)
		{
			EdgeInfo<int> temp;
			h.removeMinValue(temp);
			if (in_S_or_in_T[temp.u] == false || in_S_or_in_T[temp.v] == false)
			{
				if (in_S_or_in_T[temp.u])
					swap(temp.u, temp.v);
				in_S_or_in_T[temp.u] = true;
				_graph.insertEdge(temp.u, temp.v);
				for (size_t p = 0; p != in_S_or_in_T.size(); ++p)
				{
					if (in_S_or_in_T[p] == false)
					{
						if (temp.u < p)
						{
							if (_edge[temp.u][p - temp.u - 1].first)
							{
								h.insert(EdgeInfo<int>(temp.u, p, _edge[temp.u][p - temp.u - 1].second));
							}
						}
						else
						{
							if (_edge[p][temp.u - p - 1].first)
							{
								h.insert(EdgeInfo<int>(p, temp.u, _edge[p][temp.u - p - 1].second));
							}
						}
					}
				}
				break;
			}
		}
	}
	size_t EdgeNum;
	int WeightSum;
	edgeNumAndWeightSum(_graph, EdgeNum, WeightSum, EdgeWeightInfo);
	cout << "Prim算法边数" << EdgeNum << "权重和" << WeightSum<<endl;
	edgeNumAndWeightSum(g, EdgeNum, WeightSum, EdgeWeightInfo);
	cout << "Kruskal算法边数" << EdgeNum << "权重和" << WeightSum << endl;
	return 0;
}

Prim算法 与 Kruskal算法 求最小生成树 一、Prim算法 普利姆(Prim)算法适用于求解无向图中的最小生成树(Minimum Cost Spanning Tree)。下面是Prim算法构造最小生成树的过程图解。                            &nbsp... 阅读详情

相关推荐

图的最小生成树之Prim算法及Kruskal算法

最小生成树 定义:无向图连通图G中,由所有顶点构成且总价值(连接权值和)最低的一棵树(拓扑结构)称为一个最小生成树。 最小生成树顶点为|V|个,边数为|V|-1,没有圈。 对任一生成树T,如果将图中一条不属于T的边添加至T,则会产生一个圈,从该圈中除去任意一条边,则会又恢复成生成树。 下图为一示例: 对于上面的无向有权连通图,其最小生成树为: 解决最小生成树问题有两种算法Prim算法和...

SanFancsgo的博客 5236

图解最小生成树问题:Kruskal算法和Prim算法

本文全面介绍了两类经典算法,用于解决无向图中的最小生成树(MST)问题。文章解释了最小生成树的概念,并详细对比分析了Kruskal和Prim两种算法的原理、特点及应用场景。文章重点以图文并茂的方式,通过示例演示了算法的执行过程,包括详细的步骤解析和权值图示。Kruskal算法侧重边的逐步加入,适用于稀疏图;Prim算法侧重点的逐步扩张,适用于稠密图。两者均采用贪心策略,在网络设计、电路布线等领域有着广泛的应用。

m0_74496615的博客 2696

最小生成树——kruskal算法和prim算法

1.最小生成树定义 在一张带权的无向连通图中,各边权和最小的一颗生成树即为最小生成树。 2.最小生成树的应用价值 在现实生活中,很多布线问题,通线网络等问题,都可以直接或者间接的转化成最小生成树的问题去给出花费最小的方案。 3.计算最小生成树的两种算法 计算最小生成树可以采用两种方式,即Kruscarl算法和Prim算法。这两种算法都采用了贪心策略。 看过的一本书上解释说,这两...

Jane_96的博客 3019

最小生成树(Prim算法,Kruskal算法)

用Prim算法和Kruskal两种算法实现构建并输出最小生成树

m0_63223213的博客 7991

最小生成树(prim算法,kruskal算法)

对于边上有权的图来说,边权值和最小的生成树叫做这个图的最小生成树。如果一个图的边权值都不相同那么最小生成树是唯一的。 求无向图的最小生成树主要有prim算法和kruskal算法两个。 prim算法思想:设有两个点的集合:U和T,整个过程就是把T中的点不断放进U中,但是次序影响了树的形成,最佳的次序就是最小生成树的产生基础。从U选一个点q1,从T中选一个点q2,使得形成的边的权最小,将q2并入U

theArcticOcean 2824

最小生成树Prim算法和Kruskal算法

最小生成树Prim算法和Kruskal算法实验报告1.问题2.解析1.Prim算法2.Kruskal算法3.设计Prim算法:Kruskal算法:4.分析Pime算法:Kruskal算法:5.源码 实验报告 课程名称 《算法分析与设计》 实验日期 2021年 3月8日 至 2021年 3 月15日 学生姓名 钟恺 所在班级 软工192 学号 2019212212265 实验名称 最小生成树Prim算法和Kruskal算法 实验地点 精思苑2号楼208

zkpj12的博客 767

数据结构C++——最小生成树之Prim算法和Kruskal算法

数据结构C++——最小生成树之Prim算法和Kruskal算法 文章目录数据结构C++——最小生成树之Prim算法和Kruskal算法一、最小生成树的基本概念二、最小生成树之Prim算法①Prim算法的实现原理②Prim算法中的Min函数的实现③Prim算法的代码实现④测试的完整代码三、最小生成树之Kruskal算法①Kruskal算法的实现原理②Krusal算法的代码实现③测试的完整代码四、总结 一、最小生成树的基本概念 最小生成树: 在一个连通网的所有生成树中,各边的代价之和最小的那棵生成树称为该连通网

qq_54162207的博客 8319

图论之最小生成树 Prim算法和Kruskal算法

1.最小生成树问题 最小生成树问题:一个图有V个顶点,找到V-1条边连接这V个顶点,使得总权值最小 最小生成树问题通常是针对带权无向图、连通图 如果图不是连通图:分别在每个连通分量上计算最小生成树---最小生成森林 应用:电缆布线设计、网络设计、电路设计 ...

与 1644

最小生成树—Kruskal算法和Prim算法

求图的最小生成树的两种算法Kruskal算法和Prim算法解析

终为nullptr 2279

最小生成树-prim、kruskal算法

学习之前建议温习一下迪杰斯特拉算法和并查集~先简单认识下最小生成树:最小生成树是,即:以最小的成本(边的权值)将图中所有节点链接到一起。图中有n个节点,那么一定可以用n-1条边将所有节点连接到一起。那么就是最小生成树算法的任务所在。下面我们以一道模板题来讲解如何解决这个问题~~

qq_73704268的博客 1000

SmsForwarder v6.4.0 + Flask API 实战:5步搭建手机验证码自动化接收服务

本文详细介绍了如何利用SmsForwarder v6.4.0和Flask API构建企业级验证码自动化处理系统。通过5个关键步骤,包括系统架构设计、Android端配置、Flask服务端实现、企业级部署方案以及实战应用场景扩展,帮助开发者高效处理短信验证码,提升自动化测试和数据采集的工作效率。

weixin_30292745的博客 392

最小生成树Kruskal、Prim算法C++

Kruskal算法和prim算法解决图的最小生成树问题,使用C++语言实现

Brant_zero的博客 1158

win10系统下使用Mask_Rcnn训练自己的数据

版权所有,翻版必究。https://mp.youkuaiyun.com/console/editor/html/106094147 运行环境:WIN10,pycharm,相应的CUDA,CUDNN,tensorflow1.15.0,tensorflow-gpu-1.14.0,Anaconda3 第一步:Mask RCNN开源项目:https://github.com/matterport/Mask_RCNN 第一步:数据准备 首先安装labelme进行数据的标注。安装方法pip install labe

fightingxyz的博客 1750

最小生成树 -- prim算法以及Kruskal算法实现

最小生成树 基本概念: 最小生成树: 将n个顶点的图联通,最少只需要n - 1条边,构建最小生成树的目的是将各个 顶点连通起来且权值和最小。 子图: 从原图中选中一些顶点和边组成的图,称为原图的子图。 生成子图: 在原图中选中一些边和所有顶点组成的图,称为原图的生成子图 生成树: 如果生成子图恰好是一棵树,则成为生成树(无环路的连通图) 最小生成树: 权值之和最小的生成树,则成为最小生成树 prim算法(避圈法)实现最小生成树 核心思想: 通过选点产生最小生成树。 把已经生成树中的节点看作是一个集合,把剩下

Bananaaay的博客 2444

【mip-NeRF】使用一组二维图像渲染3D场景视频(mip-NeRF论文复现)

本文对mip-NeRF模型的pytorch实现进行了复现

Ryan2k的博客 1841

COSMO-RS理论:流体相热力学预测的核心模型与技术突破

摘要:COSMO-RS模型通过量子化学计算分子表面电荷分布,实现了从微观量子尺度到宏观化工过程的热力学预测。该模型基于介电连续介质理论,将分子表面片段化处理,通过σ-剖面描述电荷分布,并计算片段间的静电失配能和氢键能。其核心算法通过自洽化学势方程求解活度系数,克服了传统模型依赖实验参数的局限。随着技术进步,模型引入了高阶描述符和色散力修正,提升了预测精度。在药物研发、化工分离等领域广泛应用,但仍存在对长程有序结构预测不足等局限性。该模型为复杂体系的热力学性质预测提供了重要理论工具。

ASKCOS博客 972

【算法笔记】Kruskal/Prim算法——求解最小生成树问题

最小生成树问题:给定一张带权无向图G,求它的一棵生成树,使其中所有边权之和最小。本文将介绍针对这种问题的两种经典算法——Kruskal和Prim。

天生我材必有用,千金散尽还复来。 4946

Flink Web UI 如何使用和调试保姆级教程(持续更新)

Running Jobs(运行中的作业):显示正在运行的所有 Flink 作业的列表。每个作业都有一个独特的 Job ID,可以点击进入查看作业的详细信息。Completed Jobs(已完成的作业):显示已经完成或取消的作业列表。:显示当前集群中所有 TaskManager 的健康状态,包括 CPU 使用率、内存使用情况、Slot 数量等。Job Manager Configuration(JobManager 配置):显示 JobManager 的一些配置参数,帮助调试和优化 Flink 集群。

大模型大数据攻城狮的专栏 3987

最小生成树算法——Kruskal算法、Prim算法、堆优化的Prim算法

什么叫最小生成树? 已知一个无向连通图,那么这个图的最小生成树是该图的一个子图,且这个子图是一棵树且把图中所有节点连接到一起了。一个图可能拥有多个生成树。一个带权重的无向连通图的最小生成树(minimum spanning tree),它的权重和是小于等于其他所有生成树的权重和的。 生成树的权重和,是把生成树的每条边上的权重加起来的和。 一颗最小生成树有多少条边? 已知带权重无向连通图有V...

anlian523的博客 1万+

python如何给声音增加回声效果

创建任何声音对象的回声效果。使用sndarray和numpy来创建原始声音的偏移和衰减副本。目前它只是使用硬编码的值来设置回声的数量和延迟。你可以根据自己的需要轻松地重新创建。这段注释说明了make_echo函数的用途和实现方式,即通过pygame的sndarray模块和numpy库来处理声音数据,生成具有回声效果的声音。函数中使用了固定的回声数量和延迟时间,但这些值可以根据用户的需求进行调整。

zhangzhechun的专栏 976

EPLAN 电气制图(六):电机正反转副勾主电路绘制

【插入】→【设备】→选择 “SIE.3RV2011-1AA15”(Q1)和 “SIE.1TL0001-1DB3”(M1),放置于图纸左侧。生成端子排 X3:【端子排导航器】→新建编号 “1-20”,部件 “PXC.3211814”,放置于电机上方,功能文本标注 “电机端子”。属性设置:双击结构盒,在 “显示设备标识符” 中输入位置代号(如 “+ 柜外”),并在 “格式” 选项卡中调整线型与颜色。实用技巧:勾选【选项】→【设置】→【图形的编辑】中的 “绘制带有空白区域的结构盒”,可使元件布局更清晰。

电工 2030

浅谈Prim,Kruskal最小生成树算法

由于学的最小生成树比较浅显,所写的文章可能也比较粗略,跪求大佬能指导。 首先先了解生成树的概念,什么是生成树呢?生成树可不是树,而是包含图中全部顶点的极小连通子图罢了,就是长得像棵树。而最小生成树则需要提到权值,权值是无向图生成树上各边的权值之和称为该生成树的代价,则最小生成树就是代价最小的生成树。 ...

ghj445_的博客 1775

运维工程师面试整理-安全常见安全漏洞及修复

暴露在互联网的服务和端口可能会成为攻击者的目标,例如开放的SSH、FTP、Telnet等。:攻击者通过注入恶意脚本,使其在其他用户的浏览器中执行,从而窃取用户信息或劫持用户会话。:通过插入恶意SQL代码,攻击者可以操纵应用程序的数据库查询,执行未授权的数据库操作。:展示你对新兴安全威胁和防护技术的了解和学习能力,如零信任架构、基于AI的安全分析等。在不同的服务器或沙盒环境中处理和存储上传的文件,避免在Web根目录下保存可执行文件。采用安全框架和标准(如OWASP、NIST),确保系统和应用的安全合规性。

不务正业的猿 922

最小生成树:Prim算法和Kruskal算法

由于Kruksal算法是对边进行操作,先取出边,然后判断边的两个节点,这样的话,如果一个图结构非常的稠密,那么Kruksal算法就比较慢了,而Prim算法只是对节点进行遍历,并使用set进行标记,因此会相对于Kruksal算法,在稠密图方面好很多,因此。Kruskal算法也是一种贪心算法,它将图中所有边按照权值从小到大排序,然后从权值最小的边开始,每次选择一条不构成环路的边加入到生成树中,直到所有顶点都被加入。如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出 `orz`。

Blueis_oss的博客 1331

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

用Prim和Kruskal两种算法,求解最小生成树

用Prim和Kruskal两种算法,求解最小生成树,给出模板题以及解题代码。

青春无问西东 岁月自成芳华 4141

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

最小生成树 Prim算法和Kruskal算法

Prim算法和Kruskal算法都是基于最小生成树的MST性质的贪心策略。只是两者处理的对象不一样,一个是从点出发,一个是从边出发。 Prim算法 设源点为v1,初始时U={v1},假设补集V-U={v2,v3,v4,v5,v6}。 第一次操作从v1到v2…v5的五条路径长度中选一个最小的,选中的vi从V-U删除,加入U。 之后的操作类似,都是从所有u∈U,v∈V-U中找一个最短的边(u,v),将...

Wind__Chaser的博客 915

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

上一篇: 从布尔函数的真值表构造二元决策图
下一篇: Batcher双调排序及其实现
naturerun
博客等级 码龄12年 332粉丝 142原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值