算法:关于图的最短路径算法

这篇具有很好参考价值的文章主要介绍了算法:关于图的最短路径算法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本篇总结的是图当中的最短路径算法

Dijkstra算法

单源最短路径问题:给定一个图G = ( V , E ) G=(V,E)G=(V,E),求源结点s ∈ V s∈Vs∈V到图中每个结点v ∈ V v∈Vv∈V的最短路径。Dijkstra算法就适用于解决带权重的有向图上的单源最短路径问题,同时算法要求图中所有边的权重非负。一般在求解最短路径的时候都是已知一个起点和一个终点,所以使用Dijkstra算法求解过后也就得到了所需起点到终点的最短路径。针对一个带权有向图G,将所有结点分为两组SQS是已经确定最短路径的结点集合,在初始时为空(初始时就可以将源节点s放入,毕竟源节点到自己的代价是0),Q 为其余未确定最短路径的结点集合,每次从Q 中找出一个起点到该结点代价最小的结点u ,将uQ 中移出,并放入S中,对u 的每一个相邻结点v 进行松弛操作。松弛即对每一个相邻结点v ,判断源节点s到结点u的代价与uv 的代价之和是否比原来sv 的代价更小,若代价比原来则要将sv 的代价更新为su 与u 到v 的代价之和,否则维持原样。如此一直循环直至集合Q 为空,即所有节点都已经查找过一遍并确定了最短路径,至于一些起点到达不了的结点在算法循环后其代价仍为初始设定的值,不发生变化。Dijkstra算法每次都是选择V-S中最小的路径节点来进行更新,并加入S中,所以该算法使用的是贪心策略

Dijkstra算法存在的问题是不支持图中带负权路径,如果带有负权路径,则可能会找不到一些路径的最短路径

那么下面用一个例子来说明这个算法:

算法:关于图的最短路径算法,C++,数据结构,# 算法,算法

算法:关于图的最短路径算法,C++,数据结构,# 算法,算法
Dijkstra算法是解决最短路劲中的常用算法,它的局限性在于不能求带有负权的图

下面是代码实现的过程

		// Dijkstra求最短路径
		void Dijkstra(V vertex, vector<W>& warray, vector<size_t>& parentpath)
		{
			size_t srci = GetVertexsIndex(vertex);
			// 创建两个数组,一个数组用来存最短权值,一个数组存路径,并进行数据的初始化
			warray.resize(_vertexs.size(), W_MAX);
			parentpath.resize(_vertexs.size(), W_MAX);
			warray[srci] = W();
			parentpath[srci] = srci;
			// 用一个vector用来记录每个顶点是否都被选过了
			vector<bool> check(_vertexs.size(), false);

			// 每个顶点都用贪心算法找一次
			for (size_t num = 0; num < _vertexs.size(); num++)
			{
				// 定义一些变量,用来寻找到某个顶点最短的路径值和这个顶点的值
				W minW = W_MAX;
				size_t u = 0;
				// 首先遍历一次全部顶点,寻找从起点到该点路径最短的点
				for (size_t i = 0; i < _vertexs.size(); i++)
				{
					// 如果这个顶点没有被选过,并且这个顶点和起点之间联通,就把它选进来
					if (check[i] == false && warray[i] != W_MAX && warray[i] < minW)
					{
						minW = warray[i];
						u = i;
					}
				}
				// 运行到这里,就找出了到起点位置距离最短的顶点和具体的值,分别为minw和u
				check[u] = true;
				// 此时进行松弛算法,更新这个点到周围延伸出的顶点的路径值
				for (size_t j = 0; j < _vertexs.size(); j++)
				{
					// _vertexs[j]这个顶点经过_vertexs[u]到起点的距离小于它现在的值,那么就进行更新
					if (check[j] == false && _matrix[u][j] != W_MAX && warray[u] + _matrix[u][j] < warray[j])
					{
						// 此时说明可以进行更新
						warray[j] = warray[u] + _matrix[u][j];
						parentpath[j] = u;
					}
				}
			}
		}

为了便于观察,实现一个打印路径的逻辑算法,思路还是很简单的


		// 打印最短路径的逻辑算法
		void PrinrtShotPath(const V& src, const vector<W>& dist, const vector<size_t>& parentPath)
		{
			size_t srci = GetVertexsIndex(src);
			for (size_t i = 0; i < _vertexs.size(); ++i)
			{
				if (i == srci)
					continue;
				vector<size_t> path;
				size_t parenti = i;
				while (parenti != srci)
				{
					path.push_back(parenti);
					parenti = parentPath[parenti];
				}
				path.push_back(srci);
				reverse(path.begin(), path.end());
				for (auto pos : path)
				{
					cout << _vertexs[pos] << "->";
				}
				cout << dist[i] << endl;
			}
		}

Dijkstra算法的时间复杂度是O(N^2)

Bellman-Ford算法

Dijkstra算法只能用来解决正权图的单源最短路径问题,但有些题目会出现负权图。这时这个算法就不能帮助我们解决问题了,而bellmanford算法可以解决负权图的单源最短路径问题。它的优点是可以解决有负权边的单源最短路径问题,而且可以用来判断是否有负权回路。它也有明显的缺点,它的时间复杂度 O(N*E) (N是点数,E是边数)普遍是要高于Dijkstra算法O(N²)的。像这里如果我们使用邻接矩阵实现,那么遍历所有边的数量的时间复杂度就是O(N^3),这里也可以看出来Bellman-Ford就是一种暴力求解更新

算法:关于图的最短路径算法,C++,数据结构,# 算法,算法
简单来说,Bellman算法就是一个暴力枚举的过程,虽然时间复杂度高,但是确实是可以枚举出带有负权的图的结果

		// Bellman求最短路径
		bool Bellman(V vertex, vector<W>& warray, vector<size_t>& parentpath)
		{
			size_t srci = GetVertexsIndex(vertex);
			// 创建两个数组,一个数组用来存最短权值,一个数组存路径,并进行数据的初始化
			warray.resize(_vertexs.size(), W_MAX);
			parentpath.resize(_vertexs.size(), W_MAX);
			warray[srci] = W();
			parentpath[srci] = srci;

			// 有k条边,每次更新一次边就刷新一次
			for (int k = 0; k < _vertexs.size(); k++)
			{
				for (int i = 0; i < _vertexs.size(); i++)
				{
					for (int j = 0; j < _vertexs.size(); j++)
					{
						// 运行到这里进入到邻接矩阵中,分别看一下路径长短并进行更新
						// 如果从起点到j的距离大于从起点到i,再从i到j的整体距离,此时就进行更新
						if (_matrix[i][j] != W_MAX && warray[i] + _matrix[i][j] < warray[j])
						{
							warray[j] = warray[i] + _matrix[i][j];
							parentpath[j] = i;
						}
					}
				}
			}

			// 判断一下是不是带有负权的环,如果带有环,就返回false
			for (int i = 0; i < _vertexs.size(); i++)
			{
				for (int j = 0; j < _vertexs.size(); j++)
				{
					// 如果还是能更新,就说明带负权的环了
					if (_matrix[i][j] != W_MAX && warray[i] + _matrix[i][j] < warray[j])
					{
						return false;
					}
				}
			}

			return false;
		}

Floyd-Warshall

Floyd-Warshall算法是解决任意两点间的最短路径的一种算法。

Floyd算法考虑的是一条最短路径的中间节点,即简单路径p={v1,v2,…,vn}上除v1vn的任意节点。

kp的一个中间节点,那么从i到j的最短路径p就被分成ikkj的两段最短路径p1p2p1是从ik且中间节点属于{1,2,…,k-1}取得的一条最短路径。p2是从kj且中间节点属于{1,2,…,k-1}取得的一条最短路径。

算法:关于图的最短路径算法,C++,数据结构,# 算法,算法文章来源地址https://www.toymoban.com/news/detail-826815.html

void FloydWarShall(vector<vector<W>>& vvDist, vector<vector<int>>& vvParentPath)
		{
			size_t N = _vertexs.size();
			vvDist.resize(N);
			vvParentPath.resize(N);
			// 初始化权值和路径矩阵
			for (size_t i = 0; i < N; ++i)
			{
				vvDist[i].resize(N, MAX_W);
				vvParentPath[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];
						vvParentPath[i][j] = i;
					}
					else
					{
						vvParentPath[i][j] = -1;
					}
					if (i == j)
					{
						vvDist[i][j] = 0;
						vvParentPath[i][j] = -1;
					}
				}
			}
			// 依次用顶点k作为中转点更新最短路径
			for (size_t k = 0; k < N; ++k)
			{
				for (size_t i = 0; i < N; ++i)
				{
					for (size_t j = 0; j < N; ++j)
					{
						// i->k + k->j 比 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];
							vvParentPath[i][j] = vvParentPath[k][j];
						}
					}
				}
			}
		}

到了这里,关于算法:关于图的最短路径算法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java高阶数据结构】图的最短路径问题

    图的最短路径问题! 图的基础知识博客:传送门 最短路径问题: 从在带权图的某一顶点出发,找出一条通往另一顶点的最短路径, 最短也就是沿路径各边的权值总 和达到最小 。 一共会讲解三种算法 Dijkstra算法【单源最短路径】 Bellman-Ford算法【单源最短路径】 改进:SPF

    2024年02月08日
    浏览(35)
  • 算法:关于图的最短路径算法

    本篇总结的是图当中的最短路径算法 单源最短路径问题:给定一个图 G = ( V , E ) G=(V,E)G=(V,E) ,求源结点 s ∈ V s∈Vs∈V 到图中每个结点 v ∈ V v∈Vv∈V 的最短路径。 Dijkstra 算法就适用于解决带权重的有向图上的单源最短路径问题,同时算法要求图中所有边的权重非负。一

    2024年02月19日
    浏览(34)
  • 数据结构实验任务六 :基于 Dijsktra 算法的最短路径求解

    本次代码为实验六:基于 Dijsktra 算法的最短路径求解实现。本实验的重点在于对于Dijsktra算法的理解。有关Dijsktra的资料可以参考有关博文: 图论:Dijkstra算法——最详细的分析,图文并茂,一次看懂!-CSDN博客 以下附上实现代码: 以上代码仅供参考,欢迎交流。

    2024年02月04日
    浏览(46)
  • java数据结构与算法刷题-----LeetCode1091. 二进制矩阵中的最短路径

    java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完): https://blog.csdn.net/grd_java/article/details/123063846 双分裂蛇:是求二维表中从起点到终点的经典思路(也是求无权图的最短路径问题的经典解法)。创建两条分裂蛇,分别从起点和

    2024年04月26日
    浏览(45)
  • matlab算法模型——图的最短路径和距离

    目录 一、前言 二、最短路径 1.sqarse创建稀疏矩阵 ​​2.有向图的最短路径         使用graphallshortestpaths函数 使用dijkstra.ma函数(直接引用) 3.无向图的最短路径 使用函数graphallshortestpaths(2021的版本不能用了) 使用shortestpath函数 三、未解决的问题 动态规划——求解某类问题

    2024年02月04日
    浏览(34)
  • DS图—图的最短路径(无框架)迪杰斯特拉算法

    目录 题目描述 AC代码 题目描述 给出一个图的邻接矩阵,输入顶点v,用迪杰斯特拉算法求顶点v到其它顶点的最短路径。 输入 第一行输入t,表示有t个测试实例 第二行输入顶点数n和n个顶点信息 第三行起,每行输入邻接矩阵的一行,以此类推输入n行 第i个结点与其它结点如果

    2023年04月08日
    浏览(38)
  • 详解图的最短路径算法(BFS、Dijkstra、Floyd)(附上图解步骤)

    最短路径分为两种: (1)单源路径:从某顶点出发,到其他全部顶点的最短路径 (2)顶点间的最短路径:任意两个顶点之间的最短路径 最短路径的结果主要有两个方面: (1)顶点之间最短路径的长度 (2)从源顶点到目标顶点的路径 只有边权为 1 时才能用BFS求最短路。

    2024年02月05日
    浏览(52)
  • 【数据结构】图的应用:最小生成树;最短路径;有向无环图描述表达式;拓扑排序;逆拓扑排序;关键路径

    目录 1、最小生成树 1.1 概念  1.2 普利姆算法(Prim) 1.3 克鲁斯卡尔算法(Kruskal)  2、最短路径 2.1 迪杰斯特拉算法(Dijkstra) 2.2 弗洛伊德算法(Floyd)  2.3 BFS算法,Dijkstra算法,Floyd算法的对比 3、有向无环图描述表达式 3.1 有向无环图定义及特点 3.2 描述表达式 4、拓扑排序

    2024年02月07日
    浏览(46)
  • 数据结构--最短路径 Floyd算法

    F l o y d 算法:求出每⼀对顶点之间的最短路径 color{red}Floyd算法:求出每⼀对顶点之间的最短路径 Fl oy d 算法:求出每 ⼀ 对顶点之间的最短路径 使⽤动态规划思想,将问题的求解分为多个阶段 对于n个顶点的图G,求任意⼀对顶点 V i → V j V_i to V_j V i ​ → V j ​ 之间的最短

    2024年02月12日
    浏览(36)
  • 数据结构--最短路径 Dijkstra算法

    计算  b e g i n  点到各个点的最短路 color{red}计算 begin 点到各个点的最短路 计算   b e g in   点到各个点的最短路 如果是无向图,可以先把无向图转化成有向图 我们需要2个数组 final[] (标记各顶点是否已找到最短路径)与 dis[] (最短路径⻓度)数组 Dijkstra算法是一种用于

    2024年02月12日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包