这个算法也是求单源最短路径用的,但是这个算法可以解决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. 网页 HTML表格

    今天,我开始学习了网站开发中HTML的部分内容,主要包括标签和表格. body的属性:bgcolor,background,text,topmargin,bottomargin,leftmargin, ...

  2. C#第六天

    字符串的处理练习: 课上练习1:接收用户输入的字符串,将其中的字符以与输入相反的顺序输出."abc"→"cba" 方法1: string str = " ...

  3. nmon 安装

    安装: mkdir /usr/local/nmon cd /usr/local/nmon wget http://sourceforge.net/projects/nmon/files/nmon_li ...

  4. POJ 2516 Minimum Cost

    每个物品分开做最小费用最大流. #include<cstdio> #include<cstring> #include<cmath> #include<vec ...

  5. ssh proxy配置

    在.ssh目录下新建config文件,并添加以下内容: Host 10.100.101.123 ProxyCommand=nc -X 5 -x [proxyip:proxyport] %h %p

  6. JavaScript join() 方法

    http://www.w3school.com.cn/jsref/jsref_shift.asp JavaScript Array 对象 定义和用法 join() 方法用于把数组中的所有元素放入一个字 ...

  7. hdu_1429_胜利大逃亡(续)(BFS状压)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1429 题意:迷宫的加强版,迷宫里有钥匙和门,问在指定的时间下能否逃出 题解:用二进制位来记录是否有该门 ...

  8. eclipse安卓引入库项目的正确方法

    之前清单文件里theme主题老是改不成库项目里定义好的主题@style/Theme.AppCompat.Light,只能用默认主题@style/AppTheme <application and ...

  9. QT插件和服务培训

    下载地址:http://files.cnblogs.com/files/senior-engineer/%E6%8F%92%E4%BB%B6%E5%92%8C%E6%9C%8D%E5%8A%A1%E5 ...

  10. iptables基础知识

    iptables防火墙可以用于创建过滤(filter)与NAT规则.所有Linux发行版都能使用iptables,因此理解如何配置 iptables将会帮助你更有效地管理Linux防火墙.如果你是第一 ...