最短路径算法总结(Floyd,bellmen-ford,dijkstra,Spfa)
来源:互联网 发布:mac本取消开机密码 编辑:程序博客网 时间:2024/05/16 00:56
Bellman-Ford算法
Bellman-Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题。对于给定的带权(有向或无向)图 G=(V,E),其源点为s,加权函数 w 是边集 E 的映射。对图G运行Bellman-Ford算法的结果是一个布尔值,表明图中是否存在着一个从源点s可达的负权回路。若不存在这样的回路,算法将给出从源点s到图G的任意顶点v的最短路径d[v]。
Bellman-Ford算法流程分为三个阶段:
(1)初始化:将除源点外的所有顶点的最短距离估计值 d[v] ←+∞, d[s] ←0;
(2)迭代求解:反复对边集E中的每条边进行松弛操作,使得顶点集V中的每个顶点v的最短距离估计值逐步逼近其最短距离;(运行|v|-1次)
(3)检验负权回路:判断边集E中的每一条边的两个端点是否收敛。如果存在未收敛的顶点,则算法返回false,表明问题无解;否则算法返回true,并且从源点可达的顶点v的最短距离保存在 d[v]中。
适用条件和范围:
1.单源最短路径(从源点s到其它所有顶点v);
2.有向图&无向图(无向图可以看作(u,v),(v,u)同属于边集E的有向图);
3.边权可正可负(如有负权回路输出错误提示);
4.差分约束系统;
bool bellman() { bool flag ; for(int i=0;i<n-1;i++) { flag=false; for(int j=0;j<all;j++) //穷举每条边 if(dis[t[j].to]>dis[t[j].from]+t[j].vis) //松弛判断 { dis[t[j].to]=dis[t[j].from]+t[j].vis; //松弛操作 flag=true; } if(!flag) break; } for(int k=0;k<all;k++) //对所有边进行一次遍历,判断是否有负回路 if(dis[t[k].to]>dis[t[k].from]+t[k].vis) return true; return false; }
Dijkstra算法
算法流程:
(a) 初始化:用起点v到该顶点w的直接边(弧)初始化最短路径,否则设为∞;
(b) 从未求得最短路径的终点中选择路径长度最小的终点u:即求得v到u的最短路径;
(c) 修改最短路径:计算u的邻接点的最短路径,若(v,…,u)+(u,w)<(v,…,w),则以(v,…,u,w)代替。
(d) 重复(b)-(c),直到求得v到其余所有顶点的最短路径。
特点:总是按照从小到大的顺序求得最短路径。
假设一共有N个节点,出发结点为s,需要一个一维数组vis[N]来记录前一个节点序号,一个一维数组dis[N]来记录从原点到当前节点最短路径(初始值为s到Vi的边的权值,没有则为+∞),一个二维数组map[N][N]来记录各点之间边的权重,按以上流程更新map[N]和dis[N]。
void dijs(int v)//v为原点 { int i,j,k; for(i=1;i<=n;i++) dis[i]=map[v][i];//初始化 memset(vis,0,sizeof(vis)); vis[v]=1; for(i=2;i<=n;i++) { int min=INF; k=v; for(j=1;j<=n;j++) { if(!vis[j]&&min>dis[j]) { k=j; min=dis[j];//在dis中找出最小值 } } vis[k]=1;//使k为已生成终点 for(j=1;j<=n;j++)//修改dis { if(dis[j]>dis[k]+map[k][j]) dis[j]=dis[k]+map[k][j]; } } }SPFA算法
求最短路径的算法有许多种,除了排序外,恐怕是OI界中解决同一类问题算法最多的了。最熟悉的无疑是Dijkstra,接着是Bellman-Ford,它们都可以求出由一个源点向其他各点的最短路径;如果我们想要求出每一对顶点之间的最短路径的话,还可以用Floyd-Warshall。
SPFA是这篇日志要写的一种算法,它的性能非常好,代码实现也并不复杂。特别是当图的规模大,用邻接矩阵存不下的时候,用SPFA则可以很方便地面对临接表。每个人都写过广搜,SPFA的实现和广搜非常相似。
如何求得最短路径的长度值?
首先说明,SPFA是一种单源最短路径算法,所以以下所说的“某点的最短路径长度”,指的是“某点到源点的最短路径长度”。
我们记源点为S,由源点到达点i的“当前最短路径”为D[i],开始时将所有D[i]初始化为无穷大,D[S]则初始化为0。算法所要做的,就是在运行过程中,不断尝试减小D[]数组的元素,最终将其中每一个元素减小到实际的最短路径。
过程中,我们要维护一个队列,开始时将源点置于队首,然后反复进行这样的操作,直到队列为空:
(1)从队首取出一个结点u,扫描所有由u结点可以一步到达的结点,具体的扫描过程,随存储方式的不同而不同;
(2)一旦发现有这样一个结点,记为v,满足D[v] > D[u] + w(u, v),则将D[v]的值减小,减小到和D[u] + w(u, v)相等。其中,w(u, v)为图中的边u-v的长度,由于u-v必相邻,所以这个长度一定已知(不然我们得到的也不叫一个完整的图);这种操作叫做松弛。
(3)上一步中,我们认为我们“改进了”结点v的最短路径,结点v的当前路径长度D[v]相比于以前减小了一些,于是,与v相连的一些结点的路径长度可能会相应地减小。注意,是可能,而不是一定。但即使如此,我们仍然要将v加入到队列中等待处理,以保证这些结点的路径值在算法结束时被降至最优。当然,如果连接至v的边较多,算法运行中,结点v的路径长度可能会多次被改进,如果我们因此而将v加入队列多次,后续的工作无疑是冗余的。这样,就需要我们维护一个bool数组Inqueue[],来记录每一个结点是否已经在队列中。我们仅将尚未加入队列的点加入队列。
void spfa(){int i,k;memset(vis,0,sizeof(vis));for(i=1;i<=n;i++)dis[i]=INF;//初始化 dis[1]=0;queue<int>q;//创建队列 vis[1]=1;q.push(1);//源点放入队尾 while(!q.empty()){k=q.front();//从队首取出一个节点,扫描所有从该节点可以到达的终点 q.pop();vis[k]=0;for(i=1;i<=n;i++){if(dis[i]>dis[k]+map[k][i])//松弛判断 {dis[i]=dis[k]+map[k][i];//松弛操作 if(vis[i]==0)//判断这个点是否在队列里面,如果不在加入队列 { q.push(i); vis[i]=1; }}}}}
这里需要用到动态规划的思想,对于任何一个城市而言,i 到 j 的最短距离不外乎存在经过 i 与 j 之间的k和不经过k两种可能,所以可以令k=1,2,3,...,n(n是城市的数目),再检查d(ij)与d(ik)+d(kj)的值;在此d(ik)与d(kj)分别是目前为止所知道的 i 到 k 与 k 到 j 的最短距离,因此d(ik)+d(kj)就是 i 到 j 经过k的最短距离。所以,若有d(ij)>d(ik)+d(kj),就表示从 i 出发经过 k 再到j的距离要比原来的 i 到 j 距离短,自然把i到j的d(ij)重写为d(ik)+d(kj)<这里就是动态规划中的决策>,每当一个k查完了,d(ij)就是目前的 i 到 j 的最短距离。重复这一过程,最后当查完所有的k时,d(ij)里面存放的就是 i 到 j 之间的最短距离了<这就是动态规划中的记忆化搜索>。利用一个三重循环产生一个存储每个结点最短距离的矩阵.
for i:=1 to n do
for k:=1 to n do
for(i=0;i<=m;i++) for(j=0;j<=n;j++) map[i][j]=INF;//初始化 for(k=1;k<=n;k++)//动态规划的思想 for(i=1;i<=n;i++) for(j=1;j<=n;j++) { if(i==j) continue; if(map[i][j]>map[i][k]+map[k][j]) map[i][j]=map[i][k]+map[k][j]; }
- 最短路径算法总结(Floyd,bellmen-ford,dijkstra,Spfa)
- 最短路径算法总结(Floyd,bellmen-ford,dijkstra,Spfa)
- 最短路径算法 dijkstra + floyd + spfa 【记录 总结】
- 【最短路径】:Dijkstra算法、SPFA算法、Bellman-Ford算法和Floyd-Warshall算法
- (最短路径算法整理)dijkstra、floyd、bellman-ford、spfa算法模板的整理与介绍
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
- 图的最短路径:Dijkstra、Bellman-Ford、SPFA、Floyd算法
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
- 图的最短路径:Dijkstra、Bellman-Ford、SPFA、Floyd、A*算法汇总
- 图的最短路径:Dijkstra、Bellman-Ford、SPFA、Floyd、A*算法
- 四大算法解决最短路径问题(Dijkstra+Bellman-ford+SPFA+Floyd)
- 二叉树习题之重建二叉树
- 指针与++
- 简易俄罗斯方块
- Android滑动菜单框架完全解析,教你如何一分钟实现滑动菜单特效
- android – 多屏幕适配相关
- 最短路径算法总结(Floyd,bellmen-ford,dijkstra,Spfa)
- Android adjustpan not working after the first time
- FFT
- AngularJS内置指令示例——表单验证
- shell 初始化linux系统脚本
- ListView通过OnScrollListener判断第一项数据或最后一项数据处于可视状态
- android:数据篇-SharedPreference
- 基于ICM的图像切割 MATLAB
- Leetcode ☞ 263. Ugly Number ☆ 【附求质数 prime number 最大公约gcd 最小公倍lcm】