这个算法也是求单源最短路径用的,但是这个算法可以解决Dijkstra不能解决的负权边问题。

算法要点:

1、用dis存放源点到任意一点的距离。

2、用三个数组存放输入的点到点以及点到点的距离,x【i】,y【i】,x_y_dis【i】其中表示x【i】到y【i】的距离为x_y_dis【i】。

3、循环边数,比较dis【y【i】】和dis【x【i】】+ x_y_dis【i】,然后更新dis【y【i】】,意思和Dijkstra很像,就是源点到y点的距离如果大于源点到x的距离加上x到y的距离就更新。//注意这里是y在dis前面,因为y是目的点,x到y是有方向的。

4、最外面循环点数,注意要循环N-1个点,因为N个点最短距离的最大边数不能超过N-1。

5、设置两个标识去标志,已经不能松弛了,尽早跳出循环,图有负权环路(只是进行优化处理,在模型中就不写出了)

算法模型:

for(点数-1)

{

for(边数)

{

if(dis【y【i】】> dis【x【i】】+ x_y_dis【i】)

dis【y【i】】= dis【x【i】】+ x_y_dis【i】)

}

}

算法的核心:

最外面循环第一次意思是,找到源点到目的地,经过一条边也就是进过输入时的纯x_y_dis距离比现在的距离小,那么进行松弛。

第二次循环就是,经过两条边之后的优化,因为经过一条边的最小值已经在第一次循环保存进dis中了,所以是经过两条边。

这也就很好解释为啥是N-1次循环,因为如果N个点,有N条边那一定肯定其中有回路了。

也就很好解释了为什么标识能过提前跳出循环,因为如M边的循环不能松弛的话,那么加上M+1条边就不可能再松弛了。

#include<cstdio>
#include<cstdlib>
#include<iostream> using namespace std;
/*Bellman-Ford*/ int dis[];
int x[];
int y[];
int x_y_dis[];
const int MAX = ;//定义一个最大值,距离不会超过这个 int main()
{
int i,j,q;//循环变量
int n,m;
int check=;//当这个标记为1时代表重复了,已经不能松弛了,尽早跳出循环
int flag=;//当这个标记为1时代表这个图有负权环路
cin>>n>>m;//输入N*N的图,和M条边对应的值 for (i = ; i <= n; i++)//初始化dis距离
dis[i] = MAX; for (i = ; i <= m; i++)
{
cin>>x[i]>>y[i]>>x_y_dis[i];//输入x到y的距离为z
} dis[] = ;//自己到自己肯定是0 for (q = ; q <= n-; q++)//注意最外面的循环是循环的总的点数减一个,因为两个点最多包含N-1条边
{
check = ;//如果循环结束还是1则证明没有松弛任何一个值
for (i = ; i <= m; i++)
{
if(dis[y[i]] > dis[x[i]] + x_y_dis[i])
{
dis[y[i]] = dis[x[i]] + x_y_dis[i];
check = ;
}
}
if(check == )//如果不能松弛任何一个值,那么跳出循环
break;
} if(check == )//只有最后一次循环还是有松弛的情况下才有可能出现无限松弛的负权环路
{
check=;
//判断是否有负权环路
for (i = ; i <= m; i++)
{
if(dis[y[i]] > dis[x[i]] + x_y_dis[i])
{
dis[y[i]] = dis[x[i]] + x_y_dis[i];
check = ;
}
if(check == )
break;
}
if(check == )
{
cout<<"这个图有负权回路,没有最短路径"<<endl;
}
} if(check != )//经过上面的判断只有如果没有负权回路,就输出
{
for (i = ; i <= n; i++)
{
cout<<dis[i]<<" ";
}
cout<<endl;
}
else
return ; } /* 6 9
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4
Result:0 1 8 4 13 17 5 5
2 3 2
1 2 -3
1 5 5
4 5 2
3 4 3
Result:0 -3 -1 2 4
*/

最后想提的是,这个算法的时间复杂度是O(NM)也就是当M特别多的时候(题目故意恶心你)需要进一步的优化处理,我之后再实现。

但是这个算法的优点就是能解决负边权的问题。

和Dijkstra相比,Dijkstra是在两个点之间加一个点,利用点去循环更新一个距离之后就认为这个距离已经是最优解了,后面利用最优解去不断取出后面点的最优解。而Bellman-Ford是循环输入的边,让边的不断增加去更新距离,所以当边不断的增加,距离也就更新了,无论你距离的正负。

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

  1. 最短路径算法专题2----Dijkstra

    这个算法适用于求单源最短路径,从一点出发,到其余个点的最短路径. 算法要点: 1.用二维数组存放点到点的距离-----不能相互到达的点用MAX代替距离 2.用dis数组存放源点到任意其他一点的距离-- ...

  2. Bellman—Ford算法思想

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

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

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

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

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

  5. Johnson 全源最短路径算法

    解决单源最短路径问题(Single Source Shortest Paths Problem)的算法包括: Dijkstra 单源最短路径算法:时间复杂度为 O(E + VlogV),要求权值非负: ...

  6. Floyd-Warshall 全源最短路径算法

    Floyd-Warshall 算法采用动态规划方案来解决在一个有向图 G = (V, E) 上每对顶点间的最短路径问题,即全源最短路径问题(All-Pairs Shortest Paths Probl ...

  7. Bellman-Ford 单源最短路径算法

    Bellman-Ford 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source Shortest Path)的算法.该算法由 Richard Bellman 和 Leste ...

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

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

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

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

随机推荐

  1. Zend Studio配合Xdebug调试

    以下配置均在windows环境下. 1.下载xdebug 使用phpinfo()查看当前php的版本信息: 到xdebug下载页面下载对应的xdebug版本:   将解压出的php_xdebug-2. ...

  2. grub4dos新手指南-1

    对于多数没有或很少接触过linux的windows用户来说,刚开始使用grub时离不开菜单.也就是说,使用grub前,我们要准备menu.lst文件.先讲一些最为常用的命令help用来显示其它命令的用 ...

  3. HDU 5812 Distance

    从a变到b,也就是将a一直除素因子,除到1为止,然后乘b的素因子,一直乘到b. 但是gcd(a,b)部分是不用除下去的.所以d(a,b)=a/gcd(a,b)的素因子个数+b/gcd(a,b)的素因子 ...

  4. iosUISegmentedControl的基本设置

    //创建segmentControl 分段控件 UISegmentedControl *segC = [[UISegmentedControl alloc]initWithFrame:CGRectMa ...

  5. 观看网上的N多教程有感

    MD只想说一句,我擦. 长篇大论,有个叼毛用呀,显示你文采.... 糟粕真TMD多,直接简单的步骤多好,不要显示的你有多专业,其实就是一个二逼. 还有N多论坛,扯淡的人更多.

  6. thinkphp整合系列之phpexcel生成生成excel文件

    在后台管理中会经常需要将数据生成excel表格的: php生成excel有两种方案: 一种是通过phpexcel生成xls格式的表格文件: 另一种则直接通过逗号换行生成csv格式的表格文件: 这里先讲 ...

  7. 第4章 流程控制----编写Java程序,使用while循环语句计算1+1/2!+1/3!+...+1/20!之和

    package four; public class fouronetwo { public static void main(String args[]){ double sum = 0,a = 1 ...

  8. QML中的ExclusiveGroup

    Exclusive这个单词在高中应该都学过,是互斥的意思.如果你没有上过或者还没有上到高中,那你非常棒,计算机领域的大师很多都是这么起步的. ExclusiveGroup顾名思义就是互斥分组,效果很明 ...

  9. Qt之日志输出窗口

    来源:http://blog.sina.com.cn/s/blog_a6fb6cc90101guz0.html 继上节所讲,Qt可以很容易的将一些日志信息保存到文件中,那么日志信息如何输出到窗口呢? ...

  10. 用GDB调试程序的设置 Segmentation fault(Core Dump)调试

    在写wifi库的时候碰见一个 Segmentation fault(Core Dump) 所以需要用GDB调试下. 在cmake的时候,修改CMakeLists.txt set(CMAKE_C_FLA ...