首页 > 其他分享 >最短路

最短路

时间:2024-09-07 23:25:55浏览次数:3  
标签:松弛 短路 扩展 负环 算法 dis

Bellman-Ford

这是一种暴力求解单源最短路的方法。如果图不存在负环,那么任意两点之间的最短路一定不经过相同的点。

假设 \(A\) 到 \(E\) 的最短路径为 \(A \to B \to C \to D \to E\),那么 \(A \to B \to C \to D\) 一定为 \(A\) 到 \(C\) 的最短路。

记 \(dis_{x}\) 表示起点 \(s\) 到 \(x\) 的最短路长度。假设当前已经有经过点数为 \(i\) 的最短路,那么对每条边 \(u \to v\) 都进行(记为松弛):\(dis_{v} = \min(dis_{v},dis_{u}+w)\) 的操作(初始 \(dis_{s}=0\),其余点 \(dis\) 为 \(+\infty\))。这样一定能得到点数为 \(i+1\) 的最短路。进行 \(n-1\) 次松弛就能算出最短路了。

如果在进行第 \(n\) 次松弛时,还有点的 \(dis\) 值在变小,说明存在经过点数大于 \(n\) 的最短路,即整个图存在负环。

这种算法的时间复杂度为 \(O(nm)\)。

SPFA

容易发现在 Bellman-Ford 中,存在许多无效的松弛,对于边 \(u \to v\),当 \(dis_{u}\) 从未被更新过或者 \(u \to v\) 进行过一次松弛后,\(dis_{u}\) 再也没被更新过,称此时进行的 \(u \to v\) 的是 \(No\) 的,否则称其是 \(Yes\) 的。

尝试去掉这样的无效松弛。维护一个队列,里面的点 \(u\) 进行的扩展(扩展指对一个 \(u\) 而言,\(u \to v\) 的所有松弛)是 \(Yes\) 的。每次取出队头 \(u\) 进行扩展,把更新成功且此时不在队列里的点 \(v\) 放进队列里。然后弹出 \(u\)。

当队列为空时,说明所有 \(u \to v\) 的松弛全是 \(No\) 了,此时 \(dis_{i}\) 即为正确最短路。

如果存在负环,那么队列将一直非空。这样的情况该怎么判断呢?记 \(Len_{i}\) 表示当前 \(s\) 到 \(i\) 的最短路经过的点数。如果松弛时存在一个点的 \(Len_{i}\) 大于 \(n\),就说明存在负环。

在一般图上速度很快,但能被卡成 \(O(nm)\)。

Dijkstra

Dijkstra 算法适用于非负权图。直接介绍这个算法的过程和证明吧。

过程:将节点分成两个集合 \(S\) 和 \(T\),\(S\) 表示已确定最短路的点集(即 \(dis_{i}\) 一定正确的点),\(T\) 表示 \(dis_{i}\) 不一定正确的点集。每次在 \(T\) 中选出一个最小的 \(dis\) 值的点,把该点放入 \(S\) 里,然后进行对它一次扩展。直到所有点都在 \(S\) 里。最开始把所有点放入 \(T\) 里,\(dis_{s}=0\),其余点 \(dis\) 为 \(+\infty\)。

用堆来实现,记 \(vis_{i}\) 表示 \(i\) 是否在 \(S\) 里,每次取出堆顶 \(x\),如果 \(vis_{x}\) 为 \(0\),对 \(x\) 做一遍扩展,如果 \(dis_{y}\) 成功更新就加入堆里。然后弹出 \(x\)。用 \(vis\) 的原因是同一个点会 \(x\) 多次入堆,但是第一次取出时才进行扩展。

由于每个点只可能进行一次扩展,总共最多会松弛 \(m\) 次,堆的大小最多达到 \(m\),所以该算法时间复杂度为 \(O(m \log m)\)。当图为稠密图时,直接暴力更优,时间复杂度为 \(O(n^2)\)。

证明:这个算法是正确的当且仅当每次 \(T\) 中取出的最小 \(dis\) 值一定是正确的。归纳假设 \(S\) 里的 \(p_{1},p_{2},\dots,p_{k-1}\) 里的 \(dis\) 一定是正确的。记 \(p_{k}\) 为在 \(T\) 中 \(dis\) 最小的点。如果存在一条经过了 \(T\) 中的点的路径的长度比 \(S\) 扩展而来的 \(dis_{p_{k}}\) 更小。

即 \(dis_{A} \le dis(p_{i})+w(p_{i},A)+w(B,C)+\dots+w(D,p_{k})<dis_{p_{k}}\),所以 \(dis_{A} < dis_{p_{k}}\),与 \(dis_{p_{k}}\) 在 \(T\) 中最小矛盾。故而从 \(S\) 中扩展而来的最小的 \(dis_{p_{k}}\) 的值一定是正确的。算法成立。

标签:松弛,短路,扩展,负环,算法,dis
From: https://www.cnblogs.com/xcs123/p/18402321

相关文章

  • 多源BFS解决最短路问题
    目录01矩阵飞地的数量地图中的最高点地图分析01矩阵题目思路解决这道题使用的方法是多源BFS,多源BFS区别于单源BFS的地方在于起点不是一个多个,首先将矩阵中所有的0加入队列中,创建一个和原始矩阵大小相同的矩阵dists,矩阵dists中的值为每个点距离0的最短距离,然后进行......
  • 有向图最短路径与BFS算法的研究
    有向图最短路径与BFS算法的研究引言有向图G=(V,E)的定义与例子BFS算法及其局限性特定边集E'的构造确认最短路径实现BFS并验证结果(C代码)引言在图论中,寻找最短路径是一个经典问题。广度优先搜索(BFS)是一种在无权重图(即所有边的权重相同)中找到从源节点到所有其他......
  • 有向图的最短路径与BFS算法的局限性分析
    有向图的最短路径与BFS算法的局限性分析引言有向图G=(V,E)的示例图G的邻接表表示问题描述BFS算法回顾BFS在示例图G中的应用及局限性构造E_s并证明BFS的局限性C语言实现及验证分析C语言实现的BFS算法结论引言在图论中,最短路径问题是寻找从一个结点(源结点)到......
  • [Python图论]在用图nx.shortest_path求解最短路径时,节点之间有多条边edge,会如何处理?
    问:在使用图求最短路径时,如果节点之间有多条路径,shortest_route=nx.shortest_path(G,source=start_node,target=end_node,weight='length')会如何处理,会自动选择最短那条吗?#输出图G各节点之间有多少条边edge,并给出其长度Edgesbetween103928and25508583:共2条Edge......
  • 求从一固定点到其余点的最短路算法及其matlab程序详解
    #################本文为学习《图论算法及其MATLAB实现》的学习笔记#################算法用途从一固定点到其他所有点的最短路的求法算法思想利用求任意两点间最短路的程序,即可求出从固定点到其他所有点的最短路,从而得到所有的最短路和最短距离。若想查看每条通路所包......
  • 对最长路(和最短路)的一些思考
    为了使得整篇文章显得更加人性化,咱们首先说一下最短路。声明:不是讲解知识点不是讲解知识点不是讲解知识点不是讲解知识点不是讲解知识点,整篇文章建立在默认已经会的基础之上,然后提出一些个人见解。最短路此时的SPFA显得不再重要了(,咱们进入正题,说一下dijkstra。(堆优化的)迪杰......
  • [Python办公]一文入门图论Graphs,轻松处理最短路径等问题!
            [Python办公]一文入门图论Graphs,轻松处理最短路径等问题!        图论是研究图这种数学结构的性质和应用的学科。图(Graphs)由节点(或顶点)和连接这些节点的边组成,它是一种强大的数据结构,广泛应用于各种领域。以下举例用最短距离来入门图论。入门问题: ......
  • AcWing854. Floyd求最短路
    注意:Floyd是求图里面任意两个点x,y之间的最短距离#include<cstring>#include<iostream>#include<algorithm>usingnamespacestd;constintN=210,INF=1e9;intn,m,Q;intd[N][N];voidfloyd(){//枚举1~k个中间节点,尝试通过这几个点中转来达到更短......
  • 求两点间最短路的Dijkstra算法及其matlab程序详解
    #################本文为学习《图论算法及其MATLAB实现》的学习笔记#################设源点为u0u_{0}u0​,目标......
  • C++实现的最短路径问题
    最短路径问题最短路径问题是图论中的一个经典问题,旨在寻找从一个起点到一个终点的最短路径。最常见的算法包括Dijkstra算法、Bellman-Ford算法和Floyd-Warshall算法。这些算法被广泛用于导航系统、网络路由等领域。问题描述输入:一个加权图,表示图中各节点之间的连接和权......