Dijkstra算法比较快速,但是如果遇到负边就无能为力了,而Bellman算法可以解决负边问题,只要不是负环。
这个算法数据结构没有讲过,他主要是每次对所以边进行松弛操作,进行n-1次得到最短路径。
其原理如下所述:
首先指出,图的任意一条最短路径既不能包含负权回路,也不会包含正权回路,因此它最多包含|n-1条边。
其次,从源点s可达的所有顶点如果存在最短路径,则这些最短路径构成一个以s为根的最短路径树。Bellman-Ford算法的迭代松弛操作,实际上就是按顶点距离s的层次,逐层生成这棵最短路径树的过程。
在对每条边进行1遍松弛的时候,生成了从s出发,层次至多为1的那些树枝。也就是说,找到了与s至多有1条边相联的那些顶点的最短路径;对每条边进行第2遍松弛的时候,生成了第2层次的树枝,就是说找到了经过2条边相连的那些顶点的最短路径……。因为最短路径最多只包含|v|-1 条边,所以,只需要循环|v|-1 次。
如果没有负权回路,由于最短路径树的高度最多只能是|v|-1,所以最多经过|v|-1遍松弛操作后,所有从s可达的顶点必将求出最短距离。如果 d[v]仍保持 +∞,则表明从s到v不可达。
如果有负权回路,那么第 |v|-1 遍松弛操作仍然会成功,这时,负权回路上的顶点不会收敛。

根据这个原理写出代码如下:

bool Bellman(int s,int n){fill(dis,dis+n,inf);dis[s]=0;for(int i=0;i<n-1;i++){//n-1此松弛操作 int flag=1;for(int u=0;u<n;u++) {for(int j=0;j<Adj[u].size();j++){int x=Adj[u][j].v;if(dis[u]+Adj[u][j].weight<dis[x]){dis[x]=dis[u]+Adj[u][j].weight;//松弛操作  flag=0;} }}if(flag)return true;//如果这一轮没有被松弛,直接退出 }for(int u=0;u<n;u++) //判断是否存在负环 {for(int j=0;j<Adj[u].size();j++){int x=Adj[u][j].v;if(dis[u]+Adj[u][j].weight<dis[x])return false;//还能松弛存在负环,失败 }  }return true;   }

虽然理解简单但是这个算法耗时较大,每一轮都要遍历所有边,其实由于一个顶点u的d[u]改变时,以此点出发的邻接点d[v]才可能改变,结合Bellman树的形成过程可以类比层次遍历,用一个队列存放结点,每拿出一个结点对邻接点松弛,如果能松弛且不在队列里就让其入队,直到队空(说明无负环,)或者某个结点入队超过n-1次,说明有负环。这就是SPFA算法,一般比Dijkstra算法还要快,比较高效。代码如下:

bool SPFA(int s,int n){fill(inq,inq+n,false);//记录是否入队fill(num,num+n,0);//记录入队次数fill(dis,dis+n,inf);queue<int>q;q.push(s);inq[s]=true;num[s]++;dis[s]=0;while(!q.empty()){int u=q.front();q.pop();inq[u]=false;for(int j=0;j<Adj[u].size();j++){int x=Adj[u][j].v;if(dis[u]+Adj[u][j].weight<dis[x]){dis[x]=dis[u]+Adj[u][j].weight;if(!inq[x]){q.push(x);num[x]++;inq[x]=true;if(num[x]>n-1)//负环return false;}}}       }return true;   }

此外关于最短路径还有一个Floyd算法,这里打包带走,下面是三个算法的全体代码:

#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;const int maxv=101;
const int inf=10000000;
struct node{int v,weight;
};vector<node>Adj[maxv] ;
int dis[101];//bellman算法 bool Bellman(int s,int n){fill(dis,dis+n,inf);dis[s]=0;for(int i=0;i<n-1;i++){//n-1此松弛操作 int flag=1;for(int u=0;u<n;u++) {for(int j=0;j<Adj[u].size();j++){int x=Adj[u][j].v;if(dis[u]+Adj[u][j].weight<dis[x]){dis[x]=dis[u]+Adj[u][j].weight;//松弛操作  flag=0;}   }}if(flag)return true;//如果这一轮没有被松弛,直接退出 }for(int u=0;u<n;u++) //判断是否存在负环 {for(int j=0;j<Adj[u].size();j++){int x=Adj[u][j].v;if(dis[u]+Adj[u][j].weight<dis[x])return false;//还能松弛存在负环,失败 }  }return true;   }//SPFA算法bool inq[maxv] ;int num[maxv];bool SPFA(int s,int n){fill(inq,inq+n,false);fill(num,num+n,0);fill(dis,dis+n,inf);queue<int>q;q.push(s);inq[s]=true;num[s]++;dis[s]=0;while(!q.empty()){int u=q.front();q.pop();inq[u]=false;for(int j=0;j<Adj[u].size();j++){int x=Adj[u][j].v;if(dis[u]+Adj[u][j].weight<dis[x]){dis[x]=dis[u]+Adj[u][j].weight;if(!inq[x]){q.push(x);num[x]++;inq[x]=true;if(num[x]>n-1)return false;}}}       }return true;   }//floyd算法
int d[maxv][maxv]   ;void floyd(int n){for(int k=0;k<n;k++)for(int i=0;i<n;i++)for(int j=0;j<n;j++)if(d[i][k]!=inf&&d[k][j]!=inf&&d[i][k]+d[k][j]<d[i][j])d[i][j]=d[i][k]+d[k][j];
}int main(){int n,m,s,t;int x,y,w;node temp;scanf("%d%d%d%d",&n,&m,&s,&t);for(int i=0;i<m;i++){scanf("%d%d%d",&x,&y,&w); temp.weight=w;temp.v=x;Adj[y].push_back(temp);temp.v=y;Adj[x].push_back(temp);}if(SPFA(s,n)) {for(int i=0;i<n;i++)printf("%d ",dis[i]);}return 0;}

Bellman算法和SPFA算法相关推荐

  1. Bellman-Ford算法和SPFA算法

    Belloman-Ford算法 算法介绍 Dijkstra可以解决单源无负边最短路径问题.但是当遇到含有负边的单源最短路径问题就需要使用Bellman-Ford算法来解决.Bellman-Ford算法 ...

  2. 【最短路径】:Dijkstra算法、SPFA算法、Bellman-Ford算法和Floyd-Warshall算法

    求最短路径最常用的算法有: Dijkstra算法.SPFA算法.Bellman-Ford算法和Floyd-Warshall算法. Dijkstra算法.SPFA算法.Bellman-Ford算法这三个 ...

  3. BF算法和KMP算法

    给定两个字符串S和T,在主串S中查找子串T的过程称为串匹配(string matching,也称模式匹配),T称为模式.这里将介绍处理串匹配问题的两种算法,BF算法和KMP算法. BF算法 (暴力匹配 ...

  4. Algorithm:C++语言实现之字符串相关算法(字符串的循环左移、字符串的全排列、带有同个字符的全排列、串匹配问题的BF算法和KMP算法)

    Algorithm:C++语言实现之字符串相关算法(字符串的循环左移.字符串的全排列.带有同个字符的全排列.串匹配问题的BF算法和KMP算法) 目录 一.字符串的算法 1.字符串的循环左移 2.字符串 ...

  5. 操作系统之存储管理——FIFO算法和LRU算法

    操作系统之进程调度--优先权法和轮转法(附上样例讲解) 操作系统之银行家算法-详解流程及案例数据 操作系统之多线程编程-读者优先/写者优先详解 操作系统之存储管理--FIFO算法和LRU算法 操作系统 ...

  6. 若S作主串,P作模式串,试分别写出利用BF算法和KMP算法的匹配过程。

    目   录 题目: 百度文库-答案: (1) (2) MOOC标准答案: (1) (2) mooc答案-截图: 数据结构(C语言版)-严蔚敏2007 题目: 设字符串S='aabaabaabaac', ...

  7. Prim算法和Kruskal算法

       Prim算法和Kruskal算法都能从连通图找出最小生成树.区别在于Prim算法是以某个顶点出发挨个找,而Kruskal是先排序边,每次选出最短距离的边再找. 一.Prim(普里姆算法)算法: ...

  8. 基于Huffman算法和LZ77算法的文件压缩的改进方向

    基于Huffman算法和LZ77算法的文件压缩(八) 到这里已经简单实现基于Huffman算法和LZ77算法的文件压缩, GitHub源码:点我 根据基于Huffman算法和LZ77算法的文件压缩(七 ...

  9. 最短路径Dijkstra算法和Floyd算法整理、

    转载自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html 最短路径-Dijkstra算法和Floyd算法 Dijks ...

最新文章

  1. WebShell代码分析溯源(第1题)
  2. Hey, 看看小程序的page-frame.html把~
  3. JS ajax请求参数格式( formData 、serialize)
  4. Socket 编程,一个服务器,多个客户端,互相通信
  5. python面试题之介绍一下Python中webbrowser的用法
  6. webrtc服务器janus通信方法学习二
  7. AndroidStudio断点调试
  8. 360浏览器或chrome谷歌浏览器 打不开HTTPS网站,显示您的连接不是私密连接解决办法
  9. 你真的会用搜索引擎吗
  10. w10计算机字体怎么设置在哪里设置,win10系统电脑字体设置的操作方法
  11. python 英语翻译 excel_Excel自动翻译
  12. matpower和pandapower数据的转化
  13. 移动友华PT924光猫获取超级用户方法
  14. iOS开发各种证书详解
  15. Dubbo 使用 kryo 序列化
  16. VMware虚拟机 之 NAT模式详解
  17. openwrt修改lan口地址失败_OpenWrt刷机后LAN口无法连通的问题
  18. EM算法·最大期望算法
  19. 基于纹理的印章识别分离——发票识别之一
  20. w7设置双显示器_Win7双显示器设置方法 一台电脑带两个显示器设置方法

热门文章

  1. Android 开发小仓库
  2. m_p,m_n,CStudent等变量前缀的理解
  3. 揭秘 · 阿里云第一女神 — 清宵
  4. 装置案例| MODBUS转PROFINET网关连接智能低压电动机
  5. 记录repast4py的前两个example——rndWalker和Rumer Agent
  6. 【计算机毕业设计】45.医院挂号系统
  7. 百度地图获取城市名称
  8. python培训费用大概多少-Python培训学费需要多少钱?
  9. job处理缓慢的性能问题排查与分析(r4笔记第18天)
  10. 高盛、亚马逊资深工程师:知识图谱技术与应用