一、相关定义

最短路径:求源点到某特定点的最短距离

特点:Bellman-Ford算法主要是针对有负权值的图,来判断该图中是否有负权回路或者存在最短路径的点

局限性:算法效率不高,不如SPFA算法

时间复杂度:O(mn)

【具体与dijkstra算法的比较】

Bellman-Ford算法为何需要循环n-1次来求解最短路径?Dijkstra从源点开始,更新dis[],找到最小值,再更新dis[]……每次循环都可以确定一个点的最短路。Bellman-Ford算法同样也是这样,它的每次循环也可以确定一个点的最短路,只不过代价很大,因为 Bellman-Ford每次循环都是操作所有边。既然代价这么大,相比Dijkstra 算法,Bellman-Ford算法还有啥用?因为后者可以检测负权回路啊。Bellman-Ford 算法的时间复杂度为 O(nm),其中 n 为顶点数,m 为边数。

【负权回路】

开始不懂,看了下面的图和我的算法描述后就懂了:

在循环n-1次的基础上再次遍历各边,对于所有边,只要存在一条边e(u, v)使得 dis[u] + w(u,v) < dis[v],则该图存在负权回路。

【松弛操作】

如左图所示,松弛计算之前,点B的值是8,但是点A的值加上边上的权重2,得到5,比点B的值(8)小,所以,点B的值减小为5。这个过程的意义是,找到了一条通向B点更短的路线,且该路线是先经过点A,然后通过权重为2的边,到达点B。
当然,如果出现右边这种情况,则不会修改点B的值,因为3+4>6。

二、算法描述

关键词:初始化    松弛操作

主要变量如下:

int n      表示有n个点,从1~n标号

int s,t    s为源点,t为终点

int dis[N]   dis[i]表示源点s到点i的最短路径

int pre[N]  记录路径,pre[i]表示i的前驱结点

bool vis[N]  vis[i]=true表示点i被标记

【初始化】

dis数组全部赋值为INF,pre数组全部赋值为-1(表示还不知道前驱),

dis[s] = 0 表示源点不要求最短路径(或者最短路径就是0)。

【松弛操作】

对于每一条边e(u, v),如果dis[u] + w(u, v) < dis[v],则另dis[v] = dis[u]+w(u, v)。w(u, v)为边e(u,v)的权值

注:上述循环执行至多n-1次。若上述操作没有对Distant进行更新,说明最短路径已经查找完毕或者部分点不可达,跳出循环;否则执行下次循环。

【检测负权回路】

为了检测图中是否存在负环路,即权值之和小于0的环路。

检测的方法很简单,只需在求解最短路径的 n-1 次循环基础上,再进行第 n 次循环:对于每一条边e(u, v),如果存在边使得dis[u] + w(u, v) < dis[v],则图中存在负环路,即是说改图无法求出单源最短路径。否则数组Distant[n]中记录的就是源点s到各顶点的最短路径长度。

【小结】

Bellman-Ford算法可以大致分为三个部分:

  1. 初始化所有点。每一个点保存一个值,表示从原点到达这个点的距离,将原点的值设为0,其它的点的值设为无穷大(表示不可达)。
  2. 进行循环,循环下标为从1到n-1(n等于图中点的个数)。在循环内部,遍历所有的边,进行松弛计算。
  3. 遍历途中所有的边(edge(u,v)),判断是否存在这样情况: d(v) > d (u) + w(u,v),若存在,则返回false,表示图中存在从源点可达的权为负的回路。

之所以需要第三步的原因,是因为,如果存在从源点可达的权为负的回路,则将因为无法收敛而导致不能求出最短路径。

三、代码实现

#include<iostream>
#include<stack>
using namespace std; #define MAX 10000 //假设权值最大不超过10000 struct Edge
{
int u;
int v;
int w;
}; Edge edge[10000]; //记录所有边
int dist[100]; //源点到顶点i的最短距离
int path[100]; //记录最短路的路径
int vertex_num; //顶点数
int edge_num; //边数
int source; //源点 bool BellmanFord()
{
//初始化
for (int i = 0; i < vertex_num; i++)
dist[i] = (i == source) ? 0 : MAX; //n-1次循环求最短路径
for (int i = 1; i <= vertex_num - 1; i++)
{
for (int j = 0; j < edge_num; j++)
{
if (dist[edge[j].v] > dist[edge[j].u] + edge[j].w)
{
dist[edge[j].v] = dist[edge[j].u] + edge[j].w;
path[edge[j].v] = edge[j].u;
}
}
} bool flag = true; //标记是否有负权回路 //第n次循环判断负权回路
for (int i = 0; i < edge_num; i++)
{
if (dist[edge[i].v] > dist[edge[i].u] + edge[i].w)
{
flag = false;
break;
}
} return flag;
} void Print()
{
for (int i = 0; i < vertex_num; i++)
{
if (i != source)
{
int p = i;
stack<int> s;
cout << "顶点 " << source << " 到顶点 " << p << " 的最短路径是: "; while (source != p) //路径顺序是逆向的,所以先保存到栈
{
s.push(p);
p = path[p];
} cout << source;
while (!s.empty()) //依次从栈中取出的才是正序路径
{
cout << "--" << s.top();
s.pop();
}
cout << " 最短路径长度是:" << dist[i] << endl;
} }
} int main()
{ cout << "请输入图的顶点数,边数,源点:";
cin >> vertex_num >> edge_num >> source; cout << "请输入" << edge_num << "条边的信息:\n";
for (int i = 0; i < edge_num; i++)
cin >> edge[i].u >> edge[i].v >> edge[i].w; if (BellmanFord())
Print();
else
cout << "Sorry,it have negative circle!\n"; return 0;
}

运行截图:

最短路径——Bellman-Ford算法的更多相关文章

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

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

  2. Bellman—Ford算法思想

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

  3. ACM/ICPC 之 最短路径-Bellman Ford范例(POJ1556-POJ2240)

    两道Bellman Ford解最短路的范例,Bellman Ford只是一种最短路的方法,两道都可以用dijkstra, SPFA做. Bellman Ford解法是将每条边遍历一次,遍历一次所有边可 ...

  4. Dijkstra算法与Bellman - Ford算法示例(源自网上大牛的博客)【图论】

    题意:题目大意:有N个点,给出从a点到b点的距离,当然a和b是互相可以抵达的,问从1到n的最短距离 poj2387 Description Bessie is out in the field and ...

  5. poj1860 bellman—ford队列优化 Currency Exchange

    Currency Exchange Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 22123   Accepted: 799 ...

  6. uva 558 - Wormholes(Bellman Ford判断负环)

    题目链接:558 - Wormholes 题目大意:给出n和m,表示有n个点,然后给出m条边,然后判断给出的有向图中是否存在负环. 解题思路:利用Bellman Ford算法,若进行第n次松弛时,还能 ...

  7. 单源最短路径(dijkstra算法)php实现

    做一个医学项目,当中在病例评分时会用到单源最短路径的算法.单源最短路径的dijkstra算法的思路例如以下: 如果存在一条从i到j的最短路径(Vi.....Vk,Vj),Vk是Vj前面的一顶点.那么( ...

  8. 最大流算法之EK(最短路径增广算法)

    这是网络流最基础的部分--求出源点到汇点的最大流(Max-Flow). 最大流的算法有比较多,本次介绍的是其中复杂度较高,但是比较好写的EK算法.(不涉及分层,纯粹靠BFS找汇点及回溯找最小流量得到最 ...

  9. 【算法设计与分析基础】25、单起点最短路径的dijkstra算法

    首先看看这换个数据图 邻接矩阵 dijkstra算法的寻找最短路径的核心就是对于这个节点的数据结构的设计 1.节点中保存有已经加入最短路径的集合中到当前节点的最短路径的节点 2.从起点经过或者不经过 ...

  10. 最短路径问题---Dijkstra算法详解

    侵删https://blog.csdn.net/qq_35644234/article/details/60870719 前言 Nobody can go back and start a new b ...

随机推荐

  1. 终于好像懂motan了!!!

    我依稀记得,刚到公司的时候,锋哥让我学习Maven,spring,spring MVC,mybatis,RPC:motan,Xdiamond,Jenkins,redis和Kafka.快3个月了,目前只 ...

  2. 小B的询问(莫队)

    题目描述 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重 ...

  3. atan和atan2反正切计算

    typedef struct point { double x, y; }point; //给定两个点 point a(x1,y1),b(x2,y2); 使用反三角函数atan求斜率,原型如下 flo ...

  4. Maven里面多环境下的属性过滤(配置)

    情景:通常一个项目都为分为开发环境(dev)和测试环境(test)还有正式环境(prod),如果每次一打包都要手动地去更改配置文件,例如数据库连接配置.将会很容易出差错. 解决方案:maven pro ...

  5. MySQL的日志相关内容

    本篇文章介绍一下mysql的备份和日志,由于备份时需要用到日志,所以在讲备份前,如果日志内容篇幅过长,将会把日志和备份分开单独来讲,先简单介绍一下mysql的日志相关内容. MySQL日志 日志是my ...

  6. 记一次防火墙导致greenplum装机失败及定位修复过程

    一.问题现象 20180201:15:06:25:028653 gpinitsystem:sdw1-2:gpadmin-[INFO]:--------------------------------- ...

  7. java初级应用:环境安装及配置

    相关文件下载: jdk下载路径:http://www.oracle.com/technetwork/java/javase/downloads/index.html eclipse下载路径:https ...

  8. 11 非阻塞套接字与IO多路复用(进阶)

    1.非阻塞套接字 第一部分 基本IO模型 1.普通套接字实现的服务端的缺陷 一次只能服务一个客户端! 2.普通套接字实现的服务端的瓶颈!!! accept阻塞! 在没有新的套接字来之前,不能处理已经建 ...

  9. 04 mysql 基础三 (进阶)

    mysql 基础三 阶段一 mysql 单表查询 1.查询所有记录 select * from department; ​ select * from student; ​ select * from ...

  10. 网站漏洞修复之最新版本UEditor漏洞

    UEditor于近日被曝出高危漏洞,包括目前官方UEditor 1.4.3.3 最新版本,都受到此漏洞的影响,ueditor是百度官方技术团队开发的一套前端编辑器,可以上传图片,写文字,支持自定义的h ...