Bellman-Ford算法

对于Dijkstra算法,不妨给出这样一个例子

graph LR
A((A)) -->|1| C((C))
A -->|2|D((D))
D -->|-4| C

根据Dijkstra算法的流程,选取A为源点。更新与A邻接的顶点,有C和D。选取已更新顶点中距离A的最小值,显然选择边权为1的边所连接的顶点C,并将C收入最短路集合S中,此时已经确定A->C的最短路为1。那么问题就出现了。

由于已经收入S中的顶点都视为最短路上的顶点且不可更改,因此由Dijkstra算法确定的A->C的最短路就是1。但是显然实际的最短路是A->D->C,花销为-2。

这时我们就需要使用别的方法来求出其最短路。比如Bellman-Ford以及其使用队列优化后的SPFA

Bellman-Ford的实现

Bellman-Ford算法实际上采用动态规划的思想。首先大前提是一个结论,对于有n个顶点的图,从源点到达其他任意顶点最多经过n-1条边。

定义\(dp[i][j]\),代表最多经过\(i\)条边到达顶点\(j\)的最小花销

显然\(dp[0][j] = +\infty\)

对于给定\(dp[i][j]\),考虑其最小花销,两个方面。

  1. 考虑从前一个顶点 k 到达顶点 j ,\(dp[i][j] = dp[i-1][k] + w[k->j]\)
  2. 考虑不经过新的中间顶点(即维持原状) ,\(dp[i][j] = dp[i - 1][k]\)

状态转移方程为\(dp[i][j] = min(dp[i - 1][j] , dp[i - 1][k] + w[k ->j])\)

显然在状态转移时,更新本层的状态只用到了上一层的状态,不妨加一个滚动数组优化,使用一维数组即可。

最终的代码如下

配合例题853. 有边数限制的最短路 - AcWing题库

#include <iostream>
#include <cstring>
using namespace std;
const int N = 1e5 + 20;
int n, m, k;
struct Edge
{
int v;
int u;
int w;
}edges[N];
int dist[N],last[N];
void bellman_ford()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
for (int i = 0; i < k; i++)//这里k的含义就是经过不超过k条边的最短路
{
memcpy(last, dist, N); //last保存上一层的状态。
for (auto x : edges)
{
dist[x.v] = min(dist[x.v], last[x.u] + x.w);//更新使用上一层的状态来更新
}
}
}
int main()
{
cin >> n >> m >> k;
for (int i = 0; i < m; i++)
{
int v, u, w;
cin >> v >> u >> w;
edges[i] = { v,u,w };
}
bellman_ford();
if (dist[n] > 0x3f3f3f3f / 2)
puts("impossible");
else
cout << dist[n];
return 0;
}

这里使用last数组记录上一层的状态。可以看出,当要求求出最多经过k条边的最短路时,只可以使用bellman-ford来做。同时由于动态规划更新状态不需要有序,因此可以简化图,只存储边

使用Bellman-Ford判断负值圈

所谓负值圈就是一个权值和为负数的环,如下

flowchart LR
A((A)) -->|2| B((B))
B -->|-5| C((C))
C -->|1| A

-5 + 2 + 1 = -2,这就形成了一个负环。

存在负值圈的图一定无最短路

但是使用Bellman-Ford算法可以检测出图中是否有负值圈。

使用一个数组cnt[N]维护更新到第N个节点所经过的边数。由于从源点到达其他任意顶点最多经过n-1条边,但是对于有负值圈的图,由于总是会有更小的路径,因此其经过的边数会大于n。我们仅需要检测在某次更新中cnt[i]是否会大于n-1即可

Bellman-Ford算法实现带有负权边的单源最短路的更多相关文章

  1. poj3259 bellman——ford Wormholes解绝负权问题

    Wormholes Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 35103   Accepted: 12805 Descr ...

  2. 图论(四)------非负权有向图的单源最短路径问题,Dijkstra算法

    Dijkstra算法解决了有向图G=(V,E)上带权的单源最短路径问题,但要求所有边的权值非负. Dijkstra算法是贪婪算法的一个很好的例子.设置一顶点集合S,从源点s到集合中的顶点的最终最短路径 ...

  3. 单源最短路——Bellman-Ford算法

    1.Dijkstra的局限性 Dijkstra算法是处理单源最短路径的有效算法,但它局限于边的权值非负的情况,若图中出现权值为负的边,Dijkstra算法就会失效,求出的最短路径就可能是错的. 列如以 ...

  4. Bellman - Ford 算法解决最短路径问题

    Bellman - Ford 算法: 一:基本算法 对于单源最短路径问题,上一篇文章中介绍了 Dijkstra 算法,但是由于 Dijkstra 算法局限于解决非负权的最短路径问题,对于带负权的图就力 ...

  5. Bellman—Ford算法思想

    ---恢复内容开始--- Bellman—Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题.对于给定的带权(有向或无向)图G=(V,E),其源点为s,加权函数w是边集E的映射.对图G ...

  6. 单源最短路:Dijkstra算法 及 关于负权的讨论

    描述: 对于图(有向无向都适用),求某一点到其他任一点的最短路径(不能有负权边). 操作: 1. 初始化: 一个节点大小的数组dist[n] 源点的距离初始化为0,与源点直接相连的初始化为其权重,其他 ...

  7. 模板C++ 03图论算法 1最短路之单源最短路(SPFA)

    3.1最短路之单源最短路(SPFA) 松弛:常听人说松弛,一直不懂,后来明白其实就是更新某点到源点最短距离. 邻接表:表示与一个点联通的所有路. 如果从一个点沿着某条路径出发,又回到了自己,而且所经过 ...

  8. 最短路模板(Dijkstra & Dijkstra算法+堆优化 & bellman_ford & 单源最短路SPFA)

    关于几个的区别和联系:http://www.cnblogs.com/zswbky/p/5432353.html d.每组的第一行是三个整数T,S和D,表示有T条路,和草儿家相邻的城市的有S个(草儿家到 ...

  9. 2018/1/28 每日一学 单源最短路的SPFA算法以及其他三大最短路算法比较总结

    刚刚AC的pj普及组第四题就是一种单源最短路. 我们知道当一个图存在负权边时像Dijkstra等算法便无法实现: 而Bellman-Ford算法的复杂度又过高O(V*E),SPFA算法便派上用场了. ...

  10. 【算法】单源最短路——Dijkstra

    对于固定起点的最短路算法,我们称之为单源最短路算法.单源最短路算法很多,最常见的就是dijkstra算法. dijkstra主要用的是一种贪心的思想,就是说如果i...s...t...j是最短路,那么 ...

随机推荐

  1. Java面试——VUE2&VUE3概览

    一.VUE2.0 1.对于MVVM的理解 MVVM 是 Model-View-ViewModel 的缩写. Model代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑: View 代表U ...

  2. 【Qt】开源一键代码开光神器,一行代码给你的项目施加祝福,减少Bug

    年底啦,没什么项目,想摸鱼划水没见到什么好玩的东西,看到有人分享这个,直接做个库来玩下,之后说不定会嵌到公司的项目里面去.... 效果如下,佛光普照! 输入也只需要一行命令 magic_spells: ...

  3. 到底什么样的 Java 项目用 Solon 好???

    什么样的 Java 项目用 Solon 好 就像华为讲的,不要因为爱国而特意买华为手机.Solon 也是,有需要就用不需要就跳过(按正常的需求选择): 信创需要国产化,应该用 Solon 或者 Sol ...

  4. 如果诸葛亮用C#写出师表...

    看到一篇18年的文章 "C++版<出师表>",站长觉得挺有意思的,就用C# 控制台也实现了一遍,技术上没啥难度,但复制代码费了1.2个小时,纯粹无聊写着玩,看者别在意枚 ...

  5. [转帖]数据库连接池选型 Druid vs HikariCP性能对比

    这里主要比较HikariCP 和阿里的Druid springboot 现在官方默认的数据库连接池是 HikariCP,HikariCP的性能从测试的数据上来看也是最高的. 先来看下这个著名的issu ...

  6. [转帖]centos7离线安装postgresql13

    https://www.cnblogs.com/summer-88/p/15341918.html 在一台可以联网的centos上安装postgresql源 yum install -y https: ...

  7. Python学习之九_winrm执行远程机器的cmd命令

    Python学习之九_winrm执行远程机器的cmd命令 winrm # 注意如下命令需要按照顺序执行. # 打开powershell的管理员模式进行如下的操作. set-executionpolic ...

  8. [转帖]Redis 最大客户端连接数,你了解吗?

    文章系转载,方便整理和归纳,源文地址:https://cloud.tencent.com/developer/article/1803944 1. 前言 上一篇文章<你的Redis集群撑得住吗? ...

  9. [转帖]window10下如何安装fio

    1.fio下载地址(实测有效): https://github.com/axboe/fio/releaseshttps://github.com/axboe/fio/releases 其他的地址如​​ ...

  10. [转帖]kubelet 原理解析六: 垃圾回收

    https://segmentfault.com/a/1190000022163856 概述 在k8s中节点会通过docker pull机制获取外部的镜像,那么什么时候清除镜像呢?k8s运行的容器又是 ...