Bellman-Ford模板
转载链接:http://blog.csdn.net/niushuai666/article/details/6791765
Dijkstra算法是处理单源最短路径的有效算法,但它局限于边的权值非负的情况,若图中出现权值为负的边,Dijkstra算法就会失效,求出的最短路径就可能是错的。
这时候,就需要使用其他的算法来求解最短路径,Bellman-Ford算法就是其中最常用的一个。该算法由美国数学家理查德•贝尔曼(Richard Bellman, 动态规划的提出者)和小莱斯特•福特(Lester Ford)发明。
适用条件&范围:
单源最短路径(从源点s到其它所有顶点v);
有向图&无向图(无向图可以看作(u,v),(v,u)同属于边集E的有向图);
边权可正可负(如有负权回路输出错误提示);
差分约束系统;
Bellman-Ford算法的流程如下:
给定图G(V, E)(其中V、E分别为图G的顶点集与边集),源点s,数组Distant[i]记录从源点s到顶点i的路径长度,初始化数组Distant[n]为, Distant[s]为0;
以下操作循环执行至多n-1次,n为顶点数:
对于每一条边e(u, v),如果Distant[u] + w(u, v) < Distant[v],则另Distant[v] = Distant[u]+w(u, v)。w(u, v)为边e(u,v)的权值;
若上述操作没有对Distant进行更新,说明最短路径已经查找完毕,或者部分点不可达,跳出循环。否则执行下次循环;
为了检测图中是否存在负环路,即权值之和小于0的环路。对于每一条边e(u, v),如果存在Distant[u] + w(u, v) < Distant[v]的边,则图中存在负环路,即是说改图无法求出单源最短路径。否则数组Distant[n]中记录的就是源点s到各顶点的最短路径长度。
可知,Bellman-Ford算法寻找单源最短路径的时间复杂度为O(V*E).
Bellman-Ford算法可以大致分为三个部分
第一,初始化所有点。每一个点保存一个值,表示从原点到达这个点的距离,将原点的值设为0,其它的点的值设为无穷大(表示不可达)。
第二,进行循环,循环下标为从1到n-1(n等于图中点的个数)。在循环内部,遍历所有的边,进行松弛计算。
第三,遍历途中所有的边(edge(u,v)),判断是否存在这样情况:
d(v) > d (u) + w(u,v)
则返回false,表示途中存在从源点可达的权为负的回路。
之所以需要第三部分的原因,是因为,如果存在从源点可达的权为负的回路。则 应为无法收敛而导致不能求出最短路径。
测试代码如下:(下面为有向图的Bellman-Ford算法。。。。。)
- #include<iostream>
- #include<cstdio>
- using namespace std;
- #define MAX 0x3f3f3f3f
- #define N 1010
- int nodenum, edgenum, original; //点,边,起点
- typedef struct Edge //边
- {
- int u, v;
- int cost;
- }Edge;
- Edge edge[N];
- int dis[N], pre[N];
- bool Bellman_Ford()
- {
- for(int i = 1; i <= nodenum; ++i) //初始化
- dis[i] = (i == original ? 0 : MAX);
- for(int i = 1; i <= nodenum - 1; ++i)
- for(int j = 1; j <= edgenum; ++j)
- if(dis[edge[j].v] > dis[edge[j].u] + edge[j].cost) //松弛(顺序一定不能反~)
- {
- dis[edge[j].v] = dis[edge[j].u] + edge[j].cost;
- pre[edge[j].v] = edge[j].u;
- }
- bool flag = 1; //判断是否含有负权回路
- for(int i = 1; i <= edgenum; ++i)
- if(dis[edge[i].v] > dis[edge[i].u] + edge[i].cost)
- {
- flag = 0;
- break;
- }
- return flag;
- }
- void print_path(int root) //打印最短路的路径(反向)
- {
- while(root != pre[root]) //前驱
- {
- printf("%d-->", root);
- root = pre[root];
- }
- if(root == pre[root])
- printf("%d\n", root);
- }
- int main()
- {
- scanf("%d%d%d", &nodenum, &edgenum, &original);
- pre[original] = original;
- for(int i = 1; i <= edgenum; ++i)
- {
- scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].cost);
- }
- if(Bellman_Ford())
- for(int i = 1; i <= nodenum; ++i) //每个点最短路
- {
- printf("%d\n", dis[i]);
- printf("Path:");
- print_path(i);
- }
- else
- printf("have negative circle\n");
- return 0;
- }
Bellman-Ford模板的更多相关文章
- ACM/ICPC 之 最短路径-Bellman Ford范例(POJ1556-POJ2240)
两道Bellman Ford解最短路的范例,Bellman Ford只是一种最短路的方法,两道都可以用dijkstra, SPFA做. Bellman Ford解法是将每条边遍历一次,遍历一次所有边可 ...
- 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次松弛时,还能 ...
- Bellman—Ford算法思想
---恢复内容开始--- Bellman—Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题.对于给定的带权(有向或无向)图G=(V,E),其源点为s,加权函数w是边集E的映射.对图G ...
- Bellman - Ford 算法解决最短路径问题
Bellman - Ford 算法: 一:基本算法 对于单源最短路径问题,上一篇文章中介绍了 Dijkstra 算法,但是由于 Dijkstra 算法局限于解决非负权的最短路径问题,对于带负权的图就力 ...
- bellman ford优先队列优化简介模板
#include<iostream>#include<cstdio>#include<utility>#include<queue>#include&l ...
- Dijkstra算法与Bellman - Ford算法示例(源自网上大牛的博客)【图论】
题意:题目大意:有N个点,给出从a点到b点的距离,当然a和b是互相可以抵达的,问从1到n的最短距离 poj2387 Description Bessie is out in the field and ...
- POJ 2240 Arbitrage (Bellman Ford判正环)
Arbitrage Time Limit: 1000MS Memory Limit: 65536K Total Submissions:27167 Accepted: 11440 Descri ...
- poj1860 兑换货币(bellman ford判断正环)
传送门:点击打开链接 题目大意:一个城市有n种货币,m个货币交换点,你有v的钱,每个交换点只能交换两种货币,(A换B或者B换A),每一次交换都有独特的汇率和手续费,问你存不存在一种换法使原来的钱更多. ...
- ACM/ICPC 之 Bellman Ford练习题(ZOJ1791(POJ1613))
这道题稍复杂一些,需要掌握字符串输入的处理+限制了可以行走的时间. ZOJ1791(POJ1613)-Cave Raider //限制行走时间的最短路 //POJ1613-ZOJ1791 //Time ...
随机推荐
- 20145335郝昊《网络攻防》Exp4 Adobe阅读器漏洞攻击
20145335郝昊<网络攻防>Exp4 Adobe阅读器漏洞攻击 实验内容 初步掌握平台matesploit的使用 有了初步完成渗透操作的思路 本次攻击对象为:windows xp sp ...
- Codeforces 788A Functions again - 贪心
Something happened in Uzhlyandia again... There are riots on the streets... Famous Uzhlyandian super ...
- github客户端上传代码
在window下安装github客户端上传代码 第一步:创建Github新账户 第二步:新建仓库 第三步:安装Github shell程序,地址:http://windows.github.com/ ...
- Spring的面向切面
Spring的面向切面 在应用开发中,有很多类似日志.安全和事务管理的功能.这些功能都有一个共同点,那就是很多个对象都需要这些功能.复用这些通用的功能的最简单的方法就是继承或者委托.但是当应用规模达到 ...
- v-pre原样输出&&v-once只加载一次
html <div id="app"> <div v-pre>{{message1}}</div><!--原样输出--> <b ...
- cent os下搭建简单的服务器
作为常和网络打交道的程序员,经常会遇到需要服务器的场合,比如搭建一个web服务器,一个代理服务器,又或者一个小型的游戏服务器. 我时常和朋友一起玩一款叫我的世界的游戏,为了能够长期稳定地联机玩,所以特 ...
- YOLO(Darknet官方)训练分类器
目录 1. 分类数据准备 2. Darknet配置 3. Darknet命令使用 4. cifar-10 使用示例 1. 分类数据准备 需要的文件列表: 1. train.list : 训练的图片的绝 ...
- php五大运行模式CGI,FAST-CGI,CLI,ISAPI,APACHE模式
做 php 开发的应该都知道 php 运行模式概念吧,本文将要和大家分享的是关于php目前比较常见的五大运行模式:包括cgi .fast-cgi.cli.isapi.apache模块的DLL ,下面作 ...
- Unity3d 常用的方法
1.创建物体 2.加载物体 3.寻找物体 4.添加脚本 1.创建物体 GameObject go; // Use this for initialization void Start () { go ...
- RN的第一个API-----注册组件Appregistry
首先解释下AppRegistry是JS运行所有React Native应用的入口 什么是入口? 1.在我们初始化一个react native项目的时候 默认的index.ios.js/index.i ...