最小生成树与最短路径

本文详细介绍了最小生成树的概念、Kruskal算法和Prim算法的实现过程,以及最短路径中的Dijkstra算法和Bellman-Ford算法,讨论了它们在处理负权重时的适用性。
摘要由CSDN通过智能技术生成

目录

一.最小生成树

1.1概念

 1.2Kruskal算法

 1.3Prim算法

 二.最短路径

2.11单源最短路径--Dijkstra算法

2.1.2单源最短路径--Bellman-Ford算法


一.最小生成树

1.1概念

连通图中的每一棵生成树,都是原图的一个极大无环子图,即:从其中删去任何一条边,生成树 就不在连通;反之,在其中引入任何一条新边,都会形成一条回路。

若连通图由n个顶点组成,则其生成树必含n个顶点和n-1条边。

1. 只能使用图中的边来构造最小生成树

2. 只能使用恰好n-1条边来连接图中的n个顶点

3. 选用的n-1条边不能构成回路

 1.2Kruskal算法

思路:先构造n个顶点的,不含边的图(G={V,NULL}),后面不断从边的集合中选出权值最小的那一条边,并且加入该边后不会形成回路。

核心:每次迭代时,选出一条具有最小权值,且两端点不在同一连通分量上的边,加入生成树

例如:

步骤:

1.先构造n个顶点,无边的图。

2.将原来图的边存储好,放入一个可排序的容器中,例如priority_queue,将边按权值的大小排好序。

3.后面选出权值最小的边时,将其加入图中,此时要知道该边的两个顶点与权值。所以priority_queue存储的是边的权值以及该边两边的顶点信息,可用一个结构体来表示。

4.每次选出权值最小的边时,将其加入图中时,要判断加入的边是否会形成回路,可用并查集来判断。

5.选出n-1条边,且未形成回路,即是最小生成树

代码实现:

 struct Edge   //优先级队列存储的元素
	{
		int _dsti;  //起始点下标
		int  _srci;// 目标点的下标
		W _w;		// 权值

		Edge(int srci,int dsti, const W w)
			:_dsti(dsti)
			, _srci(srci)
			, _w(w)
		{}
		bool operator>(const Edge& e) const //从小到大排列
		{
			return _w > e._w;
		}
	};
	typedef Grap<V, W, W_MAX, Direc> Self;
	W Kruskal(Self minTree)
	{
		int n = _vertexs.size();
		for (size_t i = 0; i < n; ++i)
		{
			minTree._matrix[i].resize(n, W_MAX);
		}
		priority_queue<Edge, vector<Edge>, greater<Edge>> _q; //先将边存储到的队列排好序
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < n; j++)
			{
				if (_matrix[i][j] != 0)
					_q.push(Edge(i, j, _matrix[i][j]));
			}
		}
		cout << "开始选边" << endl;
		UnionFindSet u(n);  //并查集
		int k = 0;
		W sum=W();
		while (!_q.empty())
		{
			Edge e = _q.top();
			_q.pop();
			if (!u.InSet(e._dsti, e._srci)) //若位形成回路
			{

				cout << "选出" << _vertexs[e._dsti]<<" " <<_vertexs[e._srci]<<" "<< e._w << endl;
				u.Union(e._dsti, e._srci);
				sum += e._w;
				minTree.AddEdge(_vertexs[e._dsti], _vertexs[e._srci], e._w);
				k++;
			}
		}
		if (k = n - 1)
		{
			return sum;
		}
		else
		{
			cout << "存在回路" << endl;
		}
	}

结果:创建的是上面的图

void test1()
{
	const char* str = "abcdefghi";
	Grap<char, int> g(str, strlen(str));
	g.AddEdge('a', 'b', 4);
	g.AddEdge('a', 'h', 8);
	g.AddEdge('a', 'h', 9);
	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);
	g.Print();
	cout << g.Kruskal(g) << endl;

}

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值