Bellman-Ford&&SPFA算法详解
Dijkstra在正权图上运行速度很快,但是它不能解决有负权的最短路,如下图:
Dijkstra运行的结果是(以1为原点):0 2 12 6 14;
但手算的结果,dist[4]的结果显然是5,为什么会出现这种情况呢?原因很显然,Dijkstra认为,从一个更长的边过来不会比一个更短的边过来更短(读起来很绕口,但请读者好好理解这句话!)但是由于出现了负权边,可以“救回来”,就像松弛2号节点一样。
Bellman_Ford:
知道了Dijkstra为什么不能做负权图之后,我们来看看Bellman-ford算法。它的基本思想是:图的最短路,既不会包含正环(可以不走),更不能有负环(否则一直走就可以无限小),因此最多经过n-1条边(每个节点都经过一次),bellman-ford实际上是枚举距离源点多少条边,尝试对每条边松弛的过程。请读者联系上图,自行推导一下Bellman_ford的运行过程
样例如下:
5 5
1 2 2
1 3 12
3 2 -13
2 4 4
3 5 2
朴素Bellman_Ford算法的时间复杂度是O(NM);程序如下:
- #include<iostream>
- #include<cstdio>
- #include<queue>
- #include<cstring>
- using namespace std;
- int n,m,s,dist[],v[],w[],u[],cnt,x,y,z;
- void bellman_ford(int s)
- {
- memset(dist,,sizeof(dist));
- dist[s]=;
- for(int i=;i<=n-;i++)
- {
- for(int j=;j<=m;j++)
- {
- dist[v[j]]=min(dist[v[j]],dist[u[j]]+w[j]);
- }
- }
- }
- int main()
- {
- scanf("%d %d",&n,&m);
- for(int i=;i<=m;i++)
- {
- scanf("%d %d %d",&u[i],&v[i],&w[i]);
- }
- bellman_ford();
- for(int i=;i<=n;i++)
- {
- cout<<dist[i]<<" ";
- }
- return ;
- }
SPFA:
SPFA是对Bellman_Ford算法的优化,它采用队列保存即将松弛其他点的节点,每次选与队首相连的点进行松弛,可以使用链式前向星(邻接表)实现,避免了Bellman_Ford算法许多无效的松弛操作,平均复杂度O(KM),K为平均松弛次数,也有可能被网格图卡回O(NM),是不稳定的算法。程序如下:
- #include<iostream>
- #include<cstdio>
- #include<queue>
- #include<cstring>
- using namespace std;
- int n,m,s,dist[],v[],w[],nxt[],head[],cnt,x,y,z;
- bool vis[];
- void add(int a,int b,int c)
- {
- v[++cnt]=b;
- w[cnt]=c;
- nxt[cnt]=head[a];
- head[a]=cnt;
- }
- void SPFA(int s)
- {
- memset(dist,,sizeof(dist));
- queue<int>q;
- dist[s]=;
- vis[s]=;
- q.push(s);
- while(!q.empty())
- {
- int c=q.front();
- q.pop();
- vis[c]=;
- for(int i=head[c];i;i=nxt[i])
- {
- int y=v[i];
- if(dist[y]>=dist[c]+w[i])
- {
- dist[y]=dist[c]+w[i];
- if(!vis[y])
- {
- q.push(y);
- vis[y]=;
- }
- }
- }
- }
- }
- int main()
- {
- scanf("%d %d",&n,&m);
- for(int i=;i<=m;i++)
- {
- scanf("%d%d%d",&x,&y,&z);
- add(x,y,z);
- }
- SPFA();
- for(int i=;i<=n;i++)
- {
- cout<<dist[i]<<" ";
- }
- return ;
- }
Bellman-Ford&&SPFA算法详解的更多相关文章
- 图的最短路径-----------SPFA算法详解(TjuOj2831_Wormholes)
这次整理了一下SPFA算法,首先相比Dijkstra算法,SPFA可以处理带有负权变的图.(个人认为原因是SPFA在进行松弛操作时可以对某一条边重复进行松弛,如果存在负权边,在多次松弛某边时可以更新该 ...
- SPFA 算法详解
适用范围:给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便 派上用场了. 我们约定有向加权图G不存在负权回路,即最短路径 ...
- SPFA 算法详解( 强大图解,不会都难!) (转)
适用范围:给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便 派上用场了. 我们约定有向加权图G不存在负权回路,即最短路径 ...
- SPFA算法详解
前置知识:Bellman-Ford算法 前排提示:SPFA算法非常容易被卡出翔.所以如果不是图中有负权边,尽量使用Dijkstra!(Dijkstra算法不能能处理负权边,但SPFA能) 前排提示*2 ...
- Bellman-Ford算法与SPFA算法详解
PS:如果您只需要Bellman-Ford/SPFA/判负环模板,请到相应的模板部分 上一篇中简单讲解了用于多源最短路的Floyd算法.本篇要介绍的则是用与单源最短路的Bellman-Ford算法和它 ...
- 【最短路径Floyd算法详解推导过程】看完这篇,你还能不懂Floyd算法?还不会?
简介 Floyd-Warshall算法(Floyd-Warshall algorithm),是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似.该算法名称以 ...
- BM算法 Boyer-Moore高质量实现代码详解与算法详解
Boyer-Moore高质量实现代码详解与算法详解 鉴于我见到对算法本身分析非常透彻的文章以及实现的非常精巧的文章,所以就转载了,本文的贡献在于将两者结合起来,方便大家了解代码实现! 算法详解转自:h ...
- kmp算法详解
转自:http://blog.csdn.net/ddupd/article/details/19899263 KMP算法详解 KMP算法简介: KMP算法是一种高效的字符串匹配算法,关于字符串匹配最简 ...
- 机器学习经典算法详解及Python实现--基于SMO的SVM分类器
原文:http://blog.csdn.net/suipingsp/article/details/41645779 支持向量机基本上是最好的有监督学习算法,因其英文名为support vector ...
随机推荐
- 69.Daily Temperatures(日常气温)
Level: Medium 题目描述: Given a list of daily temperatures T, return a list such that, for each day in ...
- 如何用latex画一个简单的表格
latex毫无疑问是一个十分强大的论文写作工具,所以掌握它就显得非常有意义,讲一下如何画一个简单的表格,代码如下: \begin{table}\centering\begin{tabular}{||c ...
- ES6——解构赋值
解构赋值: 注意: 1.左右两边结构必须一样 练习1,2,3 2.右边必须是个东西(有值)练习4 3.声明和赋值不能分开(必须在一句话里完成)练习5 /* 练习1: // let arr = [1,2 ...
- centos7 利用mailx发送邮件
当需要服务器定时发送邮件到自己邮箱时,一个邮件服务就很重要了,以下主要是mailx的实现,主要是利用 1.安装mailx 1 yum install mailx -y 2.使用到的配置文件只有一个 ...
- navigate连接不上Centos7+mariadb的问题
链接数据库时忽然遇到一个问题.Mac Navicat链接时报错Can’t connect to MySQL server on ‘xx.xx.xx.xx’ (61). PS. win版Navicat ...
- Oracle:同步两张表的相同字段
有一个需求需要同步两张表的相同字段,比如表A和表B,这两张表是不同的用户下的表,表结构是一样的. 一开始我简单写了一个sql语句,如下: update ord_log1 A set (A.pid, A ...
- linux性能分析工具Procs
- shell变量的声明和使用
- Sass-颜色运算
所有算数运算都支持颜色值,并且是分段运算的.也就是说,红.绿和蓝各颜色分段单独进行运算.如: p { color: #010203 + #040506; } 计算公式为 01 + 04 = 05.02 ...
- ThreadLocal的原理
ThreadLocal是一个支持泛型的java类,抛开里面的静态内部类ThreadLocalMap不说,其实它没几行代码,不信,您自己去看看.它用来干啥?类上注释说的很明白: 它能让线程拥有了自己内部 ...