当前位置: 首页 > news >正文

最小生成树

文章目录

    • 基本原理
    • Kruskal算法
    • Prim算法

基本原理

连通图中的每一棵生成树,都是原图的一个极大无环子图,即:从其中删去任何一条边,生成树就不在连通;反之,在其中引入任何一条新边,都会形成一条回路。
若连通图由n个顶点组成,则其生成树必含n个顶点和n-1条边。因此构造最小生成树的准则有三条:

  1. 只能使用图中的边来构造最小生成树
  2. 只能使用恰好n-1条边来连接图中的n个顶点
  3. 选用的n-1条边不能构成回路

构造最小生成树的方法:Kruskal算法和Prim算法。这两个算法都采用了逐步求解的贪心策略。

Kruskal算法

核心思想:每次迭代时,选出一条具有最小权值,且连接后图不形成回路,加入生成树。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. 利用优先级队列记录当前最小的边
  2. 判断是否形成回路利用并查集

并查集

template<class W>
struct Edge
{
	Edge(int srci,int dsti,W w)
		:_srci(srci)
		,_dsti(dsti)
		,_w(w)
	{}
	bool operator>(const Edge& e) const 
	{
		return _w > e._w;
	}

	int _srci;
	int _dsti;
	W _w;
};
int Kruskal(self& minT)
{
	int n = _vertexs.size();
	minT._matrix.resize(n, vector<int>(n,MAX_W));

	minT._vertexs = _vertexs;
	minT._mapIndex = _mapIndex;
	unionFindSet ufs(n);
	priority_queue<Edge, vector<Edge>, greater<Edge>> pq;
	//将所有边入队列
	for (int i = 0; i < n; ++i)
	{
		for (int j = i+1; j < n; ++j)
		{
			if (_matrix[i][j] != MAX_W)
			{
				pq.push({ i,j,_matrix[i][j] });
			}
		}
	}
	int sz = 0;
	int mincount = 0;
	// 边不在一个集合,说明不会构成环,则添加到最小生成树
	while (!pq.empty() && sz < n - 1)
	{
		Edge tmp = pq.top();
		pq.pop();

		if (ufs.isSameRoot(tmp._dsti, tmp._srci) == false)
		{
			sz++;
			mincount += tmp._w;
			minT._matrix[tmp._dsti][tmp._srci] = tmp._w;

			ufs.gather(tmp._dsti, tmp._srci);
		}
	}
	if (sz != n - 1)
	{
		return -1;
	}
	return mincount;
}
void TestGraphMinTree()
{
const char* str = "abcdefghi";
Graph<char, int> g(str, strlen(str));
g.AddEdge('a', 'b', 4);
g.AddEdge('a', 'h', 8);
g.AddEdge('b', 'c', 8);
g.AddEdge('b', 'h', 11);
g.AddEdge('c', 'i', 2);
g.AddEdge('c', 'f', 4);
g.AddEdge('c', 'd', 7);
g.AddEdge('d', 'f', 14);
g.AddEdge('d', 'e', 9);
g.AddEdge('e', 'f', 10);
g.AddEdge('f', 'g', 2);
g.AddEdge('g', 'h', 1);
g.AddEdge('g', 'i', 6);
g.AddEdge('h', 'i', 7);
Graph<char, int> kminTree;
cout << "Kruskal:" << g.Kruskal(kminTree) << endl;
kminTree.print();
}

在这里插入图片描述

Prim算法

Prim与Kruskal算法类似区别在于
Kruskal算法:从整个图寻找最小的边去试
Prim算法:从某个节点出发,先找该节点相邻最小的边,每选取一个节点,将该节点所有的边入优先级队列,在选取最小的边去试

int Prim(self& minT,const V& start)
{
	int n = _vertexs.size();
	minT._matrix.resize(n, vector<int>(n, MAX_W));

	minT._vertexs = _vertexs;
	minT._mapIndex = _mapIndex;
	unionFindSet ufs(n);
	priority_queue<Edge, vector<Edge>, greater<Edge>> pq;
	int starti = findIndex(start);
	for (int i = 0; i < n; i++)
	{
		if (_matrix[starti][i] != MAX_W)
		{
			pq.push({ starti,i,_matrix[starti][i] });
		}
	}

	int sz = 0;
	int mincount = 0;


	while (!pq.empty() && sz < n - 1)
	{
		Edge tmp = pq.top();
		pq.pop();
		// 防止成环
		if (ufs.isSameRoot(tmp._dsti, tmp._srci) == false)
		{
			sz++;
			mincount += tmp._w;
			ufs.gather(tmp._dsti, tmp._srci);
			minT._matrix[tmp._dsti][tmp._srci] = tmp._w;
			// 	新入顶点的边入队列
			for (int i = 0; i < n; i++)
			{
				if (_matrix[tmp._dsti][i] != MAX_W)
				{
					pq.push({ tmp._dsti,i,_matrix[tmp._dsti][i] });
				}
			}
		}
	}
	if (sz != n - 1)
	{
		return -1;
	}

	return mincount;

}

相关文章:

  • 厦门市同安区建设局网站/免费域名注册平台
  • 多城市分站站群cms/基础建站如何提升和优化
  • 怎么看网站做没做seo/打开官方网站
  • wordpress密码漏洞’/互联网营销具体做什么
  • wordpress怎么进入论坛/电商网站策划
  • wordpress的首页例子/电子商务与网络营销题库
  • 华为机试_HJ63 DNA序列【中等】
  • 基于XMC4800 Ethercat从站的工厂自动化解决方案
  • <Android开发> Android vold - 第四篇 vold 的NetlinkHandler类简介
  • MySql加密存储的数据,如何模糊搜索?
  • 使用FCN实现语义分割
  • 微服务简介以及架构演进
  • Orin+ GMSL (Ser 9295+Des 9296)流程分析(1)
  • 16. 【gRPC系列学习】stream.Recv、stream.Send、CloseSend实现原理
  • 基于禁忌搜索的TSP问题求解仿真输出路线规划图和收敛曲线
  • VR的内容荒漠,字节救不了
  • 通过脚手架vue-cli创建一个vue项目
  • [java]-JDBC