最短路径(bellman算法详解)
2016-05-08 11:21
513 查看
首先介绍一下bellman算法:
Bellman-ford算法是求含负权图的单源最短路径算法,效率很低,但代码很容易写。即进行持续地松弛(原文是这么写的,为什么要叫松弛,争议很大),每次松弛把每条边都更新一下,若n-1次松弛后还能更新,则说明图中有负环,无法得出结果,否则就成功完成。Bellman-ford算法有一个小优化:每次松弛先设一个标识flag,初值为FALSE,若有边更新则赋值为TRUE,最终如果还是FALSE则直接成功退出。Bellman-ford算法浪费了许多时间做没有必要的松弛,而SPFA算法用队列进行了优化,效果十分显著,高效难以想象。SPFA还有SLF,LLL,滚动数组等优化。
bellman的核心代码如下示例:
n,m分别代表点的个数和边的条数.
两个for循环注定比弗洛伊德的复杂度低 效率会更高 .这时候我就想问了 为什么一定是经过k-1轮次的操作呢~?
为啥不是k-2或者更少呢?
这里就要考虑最坏的情况了~.如果需要松弛操作的地方比较多 那么松弛的轮数也会随之增加 .
但是并不是所有情况都需要k-1轮操作 那么如何优化算法呢?
这个时候算法大牛说话了:如果在当前一轮的操作中 没有经过松弛操作 那么这个时候就已经不用继续松弛了~
所以就有了如下代码~;
这里要注意 :
只是在改变从u到v的权值
所以如果我们遇到的题目是无向图 如2544(杭电)就需要如下代码来完成操作:
这个时候这个题的主体算法就呈现出来了 这里贴上完整代码:
Bellman-ford算法是求含负权图的单源最短路径算法,效率很低,但代码很容易写。即进行持续地松弛(原文是这么写的,为什么要叫松弛,争议很大),每次松弛把每条边都更新一下,若n-1次松弛后还能更新,则说明图中有负环,无法得出结果,否则就成功完成。Bellman-ford算法有一个小优化:每次松弛先设一个标识flag,初值为FALSE,若有边更新则赋值为TRUE,最终如果还是FALSE则直接成功退出。Bellman-ford算法浪费了许多时间做没有必要的松弛,而SPFA算法用队列进行了优化,效果十分显著,高效难以想象。SPFA还有SLF,LLL,滚动数组等优化。
bellman的核心代码如下示例:
n,m分别代表点的个数和边的条数.
for(int k=1;k<=n-1;k++)//遍历点的次数 { for(int i=1;i<=m;i++)//遍历边的次数 { if(dis[v[i]]>dis[u[i]]+w[i])//如果从u到v的距离能够通过w这条边压缩路径 就要进行松弛操作 { dis[v[i]]=dis[u[i]]+w[i]; } } }
两个for循环注定比弗洛伊德的复杂度低 效率会更高 .这时候我就想问了 为什么一定是经过k-1轮次的操作呢~?
为啥不是k-2或者更少呢?
这里就要考虑最坏的情况了~.如果需要松弛操作的地方比较多 那么松弛的轮数也会随之增加 .
但是并不是所有情况都需要k-1轮操作 那么如何优化算法呢?
这个时候算法大牛说话了:如果在当前一轮的操作中 没有经过松弛操作 那么这个时候就已经不用继续松弛了~
所以就有了如下代码~;
for(int k=1;k<=n-1;k++) { check=0;//用check检查是否进行下一轮次的操作 for(int i=1;i<=m;i++) { if(dis[v[i]]>dis[u[i]]+w[i]) { dis[v[i]]=dis[u[i]]+w[i]; check=1; } } if(check==0)break; }
这里要注意 :
if(dis[v[i]]>dis[u[i]]+w[i])//如果从u到v的距离能够通过w这条边压缩路径 就要进行松弛操作 { dis[v[i]]=dis[u[i]]+w[i]; }这只是在改变单源路径的权值.
只是在改变从u到v的权值
所以如果我们遇到的题目是无向图 如2544(杭电)就需要如下代码来完成操作:
for(int k=1;k<=n-1;k++) { check=0; for(int i=1;i<=m;i++) { if(dis[v[i]]>dis[u[i]]+w[i]) { dis[v[i]]=dis[u[i]]+w[i]; check=1; } if(dis[u[i]]>dis[v[i]]+w[i]) { dis[u[i]]=dis[v[i]]+w[i]; check=1; } } if(check==0)break; }
这个时候这个题的主体算法就呈现出来了 这里贴上完整代码:
#include<stdio.h> #include<string.h> #include<stdlib.h> using namespace std; int dis[121212]; int u[121212]; int v[121212]; int w[121212]; int main() { int n,m; int check; while(~scanf("%d%d",&n,&m)) { if(n==0||m==0)break; for(int i=1;i<=m;i++) { scanf("%d%d%d",&u[i],&v[i],&w[i]); } for(int i=1;i<=n;i++) { dis[i]=0x1f1f1f1f; } dis[1]=0; for(int k=1;k<=n-1;k++) { check=0; for(int i=1;i<=m;i++) { if(dis[v[i]]>dis[u[i]]+w[i]) { dis[v[i]]=dis[u[i]]+w[i]; check=1; } if(dis[u[i]]>dis[v[i]]+w[i]) { dis[u[i]]=dis[v[i]]+w[i]; check=1; } } if(check==0)break; } printf("%d\n",dis ); } }
相关文章推荐
- Matlab学习 之 linear regression
- Prototype使用Template
- Compile FreeCAD on Windows
- codeforces 673B B. Problems for Round(模拟)
- 如何在服务器重新启动后继续使用session
- 上古时代 Objective-C 中哈希表的实现
- 集合框架--ListIterator接口
- 一个二叉排序树的实际例子
- 使用openframeworks无需配置学习新版本opengl 之二 使用自带载入图片
- Java中的Integer和int等包装类和基本数据类型简单比较
- 函数对象状态(Function Object State)获取 -- 引用传递和for_each()
- c++作业5
- hdu 2042 不容易系列之二
- Linux下python升级步骤【升级python各种问题,拟合整理】
- Sublime Text 3.0缺失Package Settings和Package Control菜单项
- Android 设置系统的返回键 和软键盘获取焦点问题
- Prototype使用Event
- hdu 2560 Buildings
- 使用CocoaPod导入第三方框架
- uwp开发————拍照