最短路径——Bellman-Ford算法
一、相关定义
最短路径:求源点到某特定点的最短距离
特点: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算法可以大致分为三个部分:
- 初始化所有点。每一个点保存一个值,表示从原点到达这个点的距离,将原点的值设为0,其它的点的值设为无穷大(表示不可达)。
- 进行循环,循环下标为从1到n-1(n等于图中点的个数)。在循环内部,遍历所有的边,进行松弛计算。
- 遍历途中所有的边(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算法的更多相关文章
- Bellman - Ford 算法解决最短路径问题
Bellman - Ford 算法: 一:基本算法 对于单源最短路径问题,上一篇文章中介绍了 Dijkstra 算法,但是由于 Dijkstra 算法局限于解决非负权的最短路径问题,对于带负权的图就力 ...
- Bellman—Ford算法思想
---恢复内容开始--- Bellman—Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题.对于给定的带权(有向或无向)图G=(V,E),其源点为s,加权函数w是边集E的映射.对图G ...
- ACM/ICPC 之 最短路径-Bellman Ford范例(POJ1556-POJ2240)
两道Bellman Ford解最短路的范例,Bellman Ford只是一种最短路的方法,两道都可以用dijkstra, SPFA做. Bellman Ford解法是将每条边遍历一次,遍历一次所有边可 ...
- Dijkstra算法与Bellman - Ford算法示例(源自网上大牛的博客)【图论】
题意:题目大意:有N个点,给出从a点到b点的距离,当然a和b是互相可以抵达的,问从1到n的最短距离 poj2387 Description Bessie is out in the field and ...
- poj1860 bellman—ford队列优化 Currency Exchange
Currency Exchange Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 22123 Accepted: 799 ...
- uva 558 - Wormholes(Bellman Ford判断负环)
题目链接:558 - Wormholes 题目大意:给出n和m,表示有n个点,然后给出m条边,然后判断给出的有向图中是否存在负环. 解题思路:利用Bellman Ford算法,若进行第n次松弛时,还能 ...
- 单源最短路径(dijkstra算法)php实现
做一个医学项目,当中在病例评分时会用到单源最短路径的算法.单源最短路径的dijkstra算法的思路例如以下: 如果存在一条从i到j的最短路径(Vi.....Vk,Vj),Vk是Vj前面的一顶点.那么( ...
- 最大流算法之EK(最短路径增广算法)
这是网络流最基础的部分--求出源点到汇点的最大流(Max-Flow). 最大流的算法有比较多,本次介绍的是其中复杂度较高,但是比较好写的EK算法.(不涉及分层,纯粹靠BFS找汇点及回溯找最小流量得到最 ...
- 【算法设计与分析基础】25、单起点最短路径的dijkstra算法
首先看看这换个数据图 邻接矩阵 dijkstra算法的寻找最短路径的核心就是对于这个节点的数据结构的设计 1.节点中保存有已经加入最短路径的集合中到当前节点的最短路径的节点 2.从起点经过或者不经过 ...
- 最短路径问题---Dijkstra算法详解
侵删https://blog.csdn.net/qq_35644234/article/details/60870719 前言 Nobody can go back and start a new b ...
随机推荐
- SpingMVC前置控制器过滤问题
/<servlet-mapping> <servlet-name>Springmvc</servlet-name> <url-pattern>/< ...
- Swift_Set详解
Swift_Set详解 点击查看源码 初始化 //初始化 fileprivate func testInit() { //空Set var set = Set<String>() prin ...
- 工具类(为控件设置圆角) - iOS
为了便于日常开发效率,因此创建了一些小的工具类便于使用.具体 code 如下:声明: /* 为控件添加边框样式_工具类 */ #import <UIKit/UIKit.h> typedef ...
- 使用poi读取excel文件 Cannot get a text value from a numeric cell
我这样转换得到一个excel文本域的值 Cell cell = row.getCell(c); cell.setCellType(Cell.CELL_TYPE_STRING); String park ...
- 用python爬取小说章节内容
在学爬虫之前, 最好有一些html基础, 才能更好的分析网页. 主要是五步: 1. 获取链接 2. 正则匹配 3. 获取内容 4. 处理内容 5. 写入文件 代码如下: #导入相关model fro ...
- C++调用WMI类查询获取操作系统名
#define _WIN32_DCOM #include <iostream> #include <comdef.h> #include <Wbemidl.h> u ...
- HDFS学习总结
1.什么是Hadoop 管理网络中跨多台计算机存储的文件系统称为分布式文件系统面临的挑战:使文件系统能容忍节点故障且不丢失任何数据不适合的特点:低时间延迟的数据访问&大量的小文件&多用 ...
- 利用PHP str_replace()函数替换符合百度MIP内容标准
了解过百度MIP的同学都知道(什么?你不知道什么是百度MIP?就是移动网页加速器鸭
- JQ 封装全选函数
单击时触发效果: 如果有一个没有选中把全选的勾去了,如果select所有的都选中了,那就把全选勾上 html里: <div class="row cl"> <la ...
- urllib,url中链接包含汉字怎么用百分号(%)加密处理
使用urllib中的quote,和unquote方法将汉字编码成gbk(2个百分号对应一个汉字)或者utf8(3个百分号对应一个汉字) 注意用%加密汉字时,汉字不能是Unicode编码格式,否则会报错 ...