C++图论核心之最短路径算法从原理到实战

 更新时间:2026年02月23日 10:41:59   作者:落羽的落羽  
这篇文章主要介绍了C++图论核心之最短路径算法,最短路径问题是指,从在带权的有向图中从某一顶点出发,找到通往另一顶点的最短路径,最短指的是沿路径各边的权值总和最小,需要的朋友可以参考下

一、Dijkstra算法

最短路径问题是指,从在带权的有向图中从某一顶点出发,找到通往另一顶点的最短路径,“最短”指的是沿路径各边的权值总和最小。

Dijkstra算法是单源最短路径的经典贪心算法,只能用于没有负权的图。它从起点出发,每次选当前距离最小且未确定最短路径的节点,用它去松弛(更新)所有邻接点的最短路径估计值,标记该节点为 “已确定”,重复此过程直到所有节点处理完毕,最终得到起点到图中所有节点的最短路径。

// src是选定的起点,dist记录起点到各点的最短路径,pPath记录到每个点的最短路径的前驱顶点下标
void Dijkstra(const V& src, vector<W>& dist, vector<int>& pPath)
{
		size_t srci = GetVertexIndex(src);
		size_t n = _vertexs.size();
		dist.resize(n, MAX_W);
		pPath.resize(n, -1);
		dist[srci] = 0;
		pPath[srci] = srci;
		// 已经确定最短路径的顶点集合
		vector<bool> S(n, false);
		for (size_t j = 0; j < n; ++j)
		{
			// 选最短路径顶点且不在S更新其他路径
			int u = 0;
			W min = MAX_W;
			for (size_t i = 0; i < n; ++i)
			{
				if (S[i] == false && dist[i] < min)
				{
					u = i;
					min = dist[i];
				}
			}
			S[u] = true;
			// 松弛更新u连接顶点v  srci->u + u->v <  srci->v  更新
			for (size_t v = 0; v < n; ++v)
			{
				if (S[v] == false && _matrix[u][v] != MAX_W
					&& dist[u] + _matrix[u][v] < dist[v])
				{
					dist[v] = dist[u] + _matrix[u][v];
					pPath[v] = u;
				}
			}
		}
}

二、Bellman_Ford算法

Bellman_Ford算法能用来解决负权图的单源最短路径问题,但是它的时间复杂度高于Dijkstra算法,本质是暴力求解。从起点出发,把图里所有边从头到尾松弛一遍,重复n次,就能算出起点到所有点的最短路径;因为任何最短路径最多只经过n‑1条边。跑完之后再扫一遍所有边,如果还能更新距离,就说明图里有负权回路,最短路径不存在。

bool BellmanFord(const V& src, vector<W>& dist, vector<int>& pPath)
{
		size_t n = _vertexs.size();
		size_t srci = GetVertexIndex(src);
		// vector<W> dist,记录srci-其他顶点最短路径权值数组
		dist.resize(n, MAX_W);
		// vector<int> pPath 记录srci-其他顶点最短路径父顶点数组
		pPath.resize(n, -1);
		// 先更新srci->srci为缺省值
		dist[srci] = W();
		// 总体最多更新n轮
		for (size_t k = 0; k < n; ++k)
		{
			// i->j 更新松弛
			bool update = false;
			cout << "更新第:" << k << "轮" << endl;
			for (size_t i = 0; i < n; ++i)
			{
				for (size_t j = 0; j < n; ++j)
				{
					// srci -> i + i ->j
					if (_matrix[i][j] != MAX_W && dist[i] != MAX_W && dist[i] + _matrix[i][j] < dist[j])
	 			    {
						update = true;
						//cout << _vertexs[i] << "->" << _vertexs[j] << ":" << _matrix[i][j] << endl;
						dist[j] = dist[i] + _matrix[i][j];
						pPath[j] = i;
					}
				}
			}
			// 如果这个轮次中没有更新出更短路径,那么后续轮次就不需要再走了
			if (update == false)
			{
				break;
			}
		}
		// 还能更新就是带负权回路
		for (size_t i = 0; i < n; ++i)
		{
			for (size_t j = 0; j < n; ++j)
			{
				// srci -> i + i ->j
				if (_matrix[i][j] != MAX_W && dist[i] + _matrix[i][j] < dist[j])
				{
					return false;
				}
			}
		}
		return true;
}

三、Floyd_Warshall算法

Floyd-Warshall算法是求任意两点之间最短路径的算法,依次把每个点当作中转点,判断从 i 到 j 是直接走更近,还是经过这个中转点 k 再走更近,不断更新所有点对的最短距离,三层循环跑完就得到全图最短路径。

void FloydWarshall(vector<vector<W>>& vvDist, vector<vector<int>>& vvpPath)
{
		size_t n = _vertexs.size();
		vvDist.resize(n);
		vvpPath.resize(n);
		// 初始化权值和路径矩阵
		for (size_t i = 0; i < n; ++i)
		{
			vvDist[i].resize(n, MAX_W);
			vvpPath[i].resize(n, -1);
		}
		// 直接相连的边更新一下
		for (size_t i = 0; i < n; ++i)
		{
			for (size_t j = 0; j < n; ++j)
			{
				if (_matrix[i][j] != MAX_W)
				{
					vvDist[i][j] = _matrix[i][j];
					vvpPath[i][j] = i;
				}
				if (i == j)
				{
					vvDist[i][j] = W();
				}
			}
		}
		// 最短路径的更新i-> {其他顶点} ->j
		for (size_t k = 0; k < n; ++k)
		{
			for (size_t i = 0; i < n; ++i)
			{
				for (size_t j = 0; j < n; ++j)
				{
					// k 作为的中间点尝试去更新i->j的路径
					if (vvDist[i][k] != MAX_W && vvDist[k][j] != MAX_W
							&& vvDist[i][k] + vvDist[k][j] < vvDist[i][j])
					{
						vvDist[i][j] = vvDist[i][k] + vvDist[k][j];
							// 找跟j相连的上一个邻接顶点
							// 如果k->j 直接相连,上一个点就k,vvpPath[k][j]存就是k
							// 如果k->j 没有直接相连,k->...->x->j,vvpPath[k][j]存就是x
						vvpPath[i][j] = vvpPath[k][j];
					}
				}
			}
		}	
}

以上就是C++图论核心之最短路径算法从原理到实战的详细内容,更多关于C++最短路径算法的资料请关注脚本之家其它相关文章!

相关文章

  • 使用Qt实现文本文件的读写操作

    使用Qt实现文本文件的读写操作

    在现代应用程序开发中,文件操作是一个不可或缺的任务,无论是读取配置文件、处理用户输入,还是保存日志信息,文件的读取和写入操作都非常重要,本文我们将展示如何通过一个简单的图形用户界面(GUI),利用QFile、QTextStream和QFileDialog类来高效地进行文件操作
    2024-06-06
  • C语言入门篇--字符串的基本理论及应用

    C语言入门篇--字符串的基本理论及应用

    本篇文章是c语言基础篇,主要为大家介绍了C语言中字符串的基本理论及应用,希望可以帮助大家快速入门c语言的世界,更好的理解c语言
    2021-08-08
  • OpenCV计算图像的水平和垂直积分投影

    OpenCV计算图像的水平和垂直积分投影

    这篇文章主要为大家详细介绍了OpenCV计算图像的水平和垂直积分投影,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-12-12
  • C++实现学生信息管理系统

    C++实现学生信息管理系统

    这篇文章主要为大家详细介绍了C++实现学生信息管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-12-12
  • C++ Boost shared_ptr共享指针详细讲解

    C++ Boost shared_ptr共享指针详细讲解

    shared_ptr是一个标准的共享所有权的智能指针,允许多个指针指向同一个对象,定义在memory文件中,命名空间为std,这篇文章主要介绍了C++ shared_ptr使用,需要的朋友可以参考下
    2022-11-11
  • 深入探讨C++ OpenCV如何实现图像矫正

    深入探讨C++ OpenCV如何实现图像矫正

    这篇文章主要为大家详细介绍了C++ OpenCV如何实现简单的图像矫正功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-03-03
  • C++ Qt属性系统详细介绍

    C++ Qt属性系统详细介绍

    这篇文章主要介绍了C++ Qt属性系统详细介绍的相关资料,需要的朋友可以参考下
    2016-12-12
  • C语言实现飞机订票系统的完整代码

    C语言实现飞机订票系统的完整代码

    为了免去在窗口排队买票的麻烦,飞机订票系统应运而生,下面这篇文章主要给大家介绍了关于C语言实现飞机订票系统的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-06-06
  • 在动态库和静态库中使用模板(dynamic libraries ,static libraries)

    在动态库和静态库中使用模板(dynamic libraries ,static libraries)

    给大家介绍一下在动态库(dynamic libraries)和静态库(static libraries)使用模板(template)的用法和解决方案。
    2017-11-11
  • C语言 实现归并排序算法

    C语言 实现归并排序算法

    这篇文章主要介绍了C语言 实现归并排序算法的相关资料,需要的朋友可以参考下
    2016-11-11

最新评论