这个算法也是求单源最短路径用的,但是这个算法可以解决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. SEO优化技巧总结

    SEO优化技巧总结 一:了解搜索引擎 基础知识 搜索引擎:由蜘蛛程序沿着链接爬行和抓取网上的大量页面,存进数据库,经过预处理,用户在搜索框 输入关键词后,搜索引擎排序从数据库中挑选出符合搜索关键词要求 ...

  2. oc 是否允许远程通知

    UIUserNotificationSettings *setting = [[UIApplication sharedApplication] currentUserNotificationSett ...

  3. 调用Lua出错

    错误提示:Could not load file or assembly 'lua51' or one of its dependencies. An attempt was made to load ...

  4. Yii2.0官方高级模板的目录结构分析

    Yii 是什么 Yii 是一个高性能,基于组件的 PHP 框架,用于快速开发现代 Web 应用程序.名字 Yii (读作 易)在中文里有"极致简单与不断演变"两重含义,也可看作 Y ...

  5. C++ : 从栈和堆来理解C#中的值类型和引用类型

    C++中并没有值类型和引用类型之说,标准变量或者自定义对象的存取默认是没有区别的.但如果深入地来看,就要了解C++中,管理数据的两大内存区域:栈和堆. 栈(stack)是类似于一个先进后出的抽屉.它的 ...

  6. centos 安装ftp服务器

    CentOS下搭建FTP服务器简单记录. 1.安装vsftpd yum install vsftpd 2.编辑iptablesvi /etc/sysconfig/iptables -A INPUT - ...

  7. php curl调用相关api

    一.基本步骤 1.本次模拟是php的相关post请求,可通过CURLOPT_CUSTOMREQUEST设定相关POST.GET.PUT.DELETE相关适应REST API 2.相关重要的是curl_ ...

  8. selenium 百度登陆

    using System;using OpenQA.Selenium;using OpenQA.Selenium.Firefox;//引用命名空间using System.IO; using Syst ...

  9. 导入Excel后绑定GridView实例

    http://blog.csdn.net/loveheronly/article/details/6715552 项目中经常用到导入导出的例子,前面做了导出的例子,现在把导入Excel的数据的例子也把 ...

  10. Volist标签

    Volist标签主要用于在模板中循环输出数据集或者多维数组. volist标签(循环输出数据) 闭合 非闭合标签 属性 name(必须):要输出的数据模板变量 id(必须):循环变量 offset(可 ...