Bellman-ford算法
来源:互联网 发布:电子产品外壳设计软件 编辑:程序博客网 时间:2024/05/23 11:38
权值的概念引入:
权值就是定义的路径上面的值。
一般来说,权值愈小,路径愈佳。
Bellman-ford算法的简介:
Bellman - ford算法是求含负权图的单源最短路径的一种算法,效率较低,代码难度较小。其原理为连续进行松弛,在每次松弛时把每条边都更新一下,若在n-1次松弛后还能更新,则说明图中有负环,因此无法得出结果,否则就完成。
松弛:
松弛就是更新两点间的最短路径。
Bellman-Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题。对于给定的带权(有向或无向)图 G=(V,E), 其源点为s,加权函数 w是 边集 E 的映射。对图G运行Bellman - Ford算法的结果是一个布尔值,表明图中是否存在着一个从源点s可达的负权回路。若不存在这样的回路,算法将给出从源点s到 图G的任意顶点v的最短路径d[v]。
- 初始化:将除源点外的所有顶点的最短距离估计值 d[v] ——>+∞, d[s]——>0;
- 迭代求解:反复对边集E中的每条边进行松弛操作,使得顶点集V中的每个顶点v的最短距离估计值逐步逼近其最短距离;(运行|v|-1次)
- 检验负权回路:判断边集E中的每一条边的两个端点是否收敛。如果存在未收敛的顶点,则算法返回false,表明问题无解;否则算法返回true,并且从源点可达的顶点v的最短距离保存在 d[v]中。
##注意:
无论是在算法导论上,还是,实际的代码比较过程中,bellman算法和dijisktra算法都非常像,但是有几个关键的不同导致了两个算法的根本不同。在松弛的过程中,dijiskstra算法中有着贪心的思路,它每一次迭代都找出了一个子问题的最短路径。并用到新的一轮迭代的过程中去,使问题的规模不断减少,因此需要用到一个visit数组来记录该节点的最短路径是否被找到。另外,在dijisktra算法中默认,路径的权值都为正数。而bellman算法中,很明显,并不是贪心的。首先它没有visit数组来记录节点的最短路径是否被找到,其次,它每次迭代的规模是一样大的,并不能减少迭代的规模。,其次,因为,在bellman算法中设置了一个检查循环,因此,用bellman算法能检查出是否存在负权环。
##代码如下:
#include<iostream>#include<cstdio>using namespace std;#define MAX 0x3f3f3f3f#define N 1010int nodenum, edgenum, original; //点,边,起点typedef struct Edge //边{ int u, v; int cost;}Edge;//边的数据结构Edge edge[N];//边int dis[N], pre[N];//距离,及其前驱bool Bellman_Ford(){ for(int i = 1; i <= nodenum; ++i) //初始化 dis[i] = (i == original ? 0 : MAX); for(int i = 1; i <= nodenum - 1; ++i)//进行nodenum-1次的松弛遍历 for(int j = 1; j <= edgenum; ++j) if(dis[edge[j].v] > dis[edge[j].u] + edge[j].cost) //松弛(顺序一定不能反~) { dis[edge[j].v] = dis[edge[j].u] + edge[j].cost; pre[edge[j].v] = edge[j].u; } //与迪杰斯特拉算法类似,但不是贪心! //并没有标记数组 //本来松弛已经结束了 //但是因为由于负权环的无限松弛性 bool flag = 1; //判断是否含有负权回路 //如果存在负权环的话一定能够继续松弛 for(int i = 1; i <= edgenum; ++i) if(dis[edge[i].v] > dis[edge[i].u] + edge[i].cost) { flag = 0; break; } //只有在负权环中才能再松弛下去 return flag;}void print_path(int root) //打印最短路的路径(反向){ while(root != pre[root]) //前驱 { printf("%d-->", root); root = pre[root]; } if(root == pre[root]) printf("%d\n", root);}int main(){ scanf("%d%d%d", &nodenum, &edgenum, &original); //输入节点的数目//输入边的数目//输入起点 pre[original] = original;//为了保存路径而保存 for(int i = 1; i <= edgenum; ++i) { scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].cost); }//u,v,起点终点。cost路径长度 if(Bellman_Ford())// for(int i = 1; i <= nodenum; ++i) //每个点最短路 { printf("%d\n", dis[i]); printf("Path:"); print_path(i); } else printf("have negative circle\n"); return 0;}
PS:终于差不多理解了。QAQ
阅读全文
1 0
- Bellman-Ford&SPFA算法
- Bellman-ford算法实现
- Bellman-Ford 算法详解
- Bellman-Ford算法
- Bellman-Ford算法
- Bellman-Ford路由算法
- Bellman-Ford算法分析
- bellman ford算法
- Bellman-Ford算法
- Bellman-Ford算法总结
- Bellman-ford算法
- bellman-ford算法
- bellman-ford 算法
- Bellman-Ford算法
- Bellman-Ford算法
- bellman ford 算法
- Bellman-Ford 算法
- Bellman-Ford算法
- Python 中用 matplotlib 画散列点 (Scatter)
- 关于oracle中blob字段查询的问题
- 前端基础进阶(七):详解面向对象、构造函数、原型与原型链
- File类:文件的删除和复制
- VMware vSphere Web Services SDK编程指南(一)-SDK简介
- Bellman-ford算法
- Java 语法分析LL1
- python---以不变形的方式调整图片大小
- BZOJ 3671 [Noi 2014] 贪心 解题报告
- Spring核心组件详解(Bean、Context、Core)
- Shell脚本实现动态配置IP与路由:解决嵌入式Android/Linux有线和无线网卡双网共存问题
- unity3d particle system优化
- 线段树:CDOJ1597-An easy problem C(区间更新的线段树)
- STM32F1时钟系统