算法-贝尔曼-福特算法
算法-贝尔曼-福特算法
注:该文是本博主记录学习之用,没有太多详细的讲解,敬请谅解!
一、简介
贝尔曼-福特算法(Bellman–Ford algorithm )用于计算出起点到各个节点的最短距离,支持存在负权重的情况
它的原理是对图进行最多V-1次松弛操作,得到所有可能的最短路径。其优于狄克斯特拉算法的方面是边的权值可以为负数、实现简单,缺点是时间复杂度过高,高达O(VE)。但算法可以进行若干种优化,提高了效率。
贝尔曼-福特算法每次对所有的边进行松弛,每次松弛都会得到一条最短路径,所以总共需要要做的松弛操作是V - 1次。在完成这么多次松弛后如果还是可以松弛的话,那么就意味着,其中包含负环。
二、场景
- 从起点出发是否存在到达各个节点的路径。
- 从起点出发到达各个节点最短路径。
- 是否存在负环路。
三、实现思路
初始化时将起点s到各个顶点v的距离dist(s->v)赋值为∞,dist(s->s)赋值为0
后续进行最多n-1次遍历操作,对所有的边进行松弛操作,假设:
所谓的松弛,以边ab为例,若dist(a)代表起点s到达a点所需要花费的总数,
dist(b)代表起点s到达b点所需要花费的总数,weight(ab)代表边ab的权重, 若存在:(dist(a) +weight(ab)) < dist(b)
则说明存在到b的更短的路径,s->…->a->b,更新b点的总花费为(dist(a) +weight(ab)),父节点为a
遍历都结束后,若再进行一次遍历,还能得到s到某些节点更短的路径的话,则说明存在负环路
四、java实现
如下图,求出A到各节点的最短路径
public class BellmanFord {/*** 实现思路:* 1、初始化时将起点起点到各个顶点的距离赋值为(无穷大)∞,当前起点距离赋值为0* 2、后续进行最多n-1次遍历操作* @param args*/public static void main(String[] args){//创建图Edge ab = new Edge("A", "B", -1);Edge ac = new Edge("A", "C", 4);Edge bc = new Edge("B", "C", 3);Edge be = new Edge("B", "E", 2);Edge ed = new Edge("E", "D", -3);Edge dc = new Edge("D", "C", 5);Edge bd = new Edge("B", "D", 2);Edge db = new Edge("D", "B", 1);//需要按图中的步骤步数顺序建立数组,否则就是另外一幅图了,//从起点A出发,步骤少的排前面Edge[] edges = new Edge[] {ab,ac,bc,be,bd,ed,dc,db};//存放到各个节点所需要消耗的时间HashMap<String,Integer> costMap = new HashMap<String,Integer>();//到各个节点对应的父节点HashMap<String,String> parentMap = new HashMap<String,String>();//初始化各个节点所消费的,当然也可以再遍历的时候判断下是否为Null//i=0的时候costMap.put("A", 0); //源点costMap.put("B", Integer.MAX_VALUE);costMap.put("C", Integer.MAX_VALUE);costMap.put("D", Integer.MAX_VALUE);costMap.put("E", Integer.MAX_VALUE);//进行节点数n-1次循环for(int i =1; i< costMap.size();i++) {boolean hasChange = false;for(int j =0; j< edges.length;j++) {Edge edge = edges[j];//该边起点目前总的路径大小int startPointCost = costMap.get(edge.getStartPoint()) == null ? 0:costMap.get(edge.getStartPoint());//该边终点目前总的路径大小int endPointCost = costMap.get(edge.getEndPoint()) == null ? Integer.MAX_VALUE : costMap.get(edge.getEndPoint());//如果该边终点目前的路径大小 > 该边起点的路径大小 + 该边权重 ,说明有更短的路径了if(endPointCost > (startPointCost + edge.getWeight())) {costMap.put(edge.getEndPoint(), startPointCost + edge.getWeight());parentMap.put(edge.getEndPoint(), edge.getStartPoint());hasChange = true;}}if (!hasChange) {//经常还没达到最大遍历次数便已经求出解了,此时可以优化为提前退出循环break;}}//在进行一次判断是否存在负环路boolean hasRing = false;for(int j =0; j< edges.length;j++) {Edge edge = edges[j];int startPointCost = costMap.get(edge.getStartPoint()) == null ? 0:costMap.get(edge.getStartPoint());int endPointCost = costMap.get(edge.getEndPoint()) == null ? Integer.MAX_VALUE : costMap.get(edge.getEndPoint());if(endPointCost > (startPointCost + edge.getWeight())) {System.out.print("\n图中存在负环路,无法求解\n");hasRing = true;break;}}if(!hasRing) {//打印出到各个节点的最短路径for(String key : costMap.keySet()) {System.out.print("\n到目标节点"+key+"最低耗费:"+costMap.get(key));if(parentMap.containsKey(key)) {List<String> pathList = new ArrayList<String>();String parentKey = parentMap.get(key);while (parentKey!=null) {pathList.add(0, parentKey);parentKey = parentMap.get(parentKey);}pathList.add(key);String path="";for(String k:pathList) {path = path.equals("") ? path : path + " --> ";path = path + k ;}System.out.print(",路线为"+path);}}}}/*** 代表"一条边"的信息对象** @author Administrator**/static class Edge{//起点idprivate String startPoint;//结束点idprivate String endPoint;//该边的权重private int weight;public Edge(String startPoint,String endPoint,int weight) {this.startPoint = startPoint;this.endPoint = endPoint;this.weight = weight;}public String getStartPoint() {return startPoint;}public String getEndPoint() {return endPoint;}public int getWeight() {return weight;}}}
五、小结
1、贝尔曼-福特算法Bellman–Ford主要用于存在负权重的方向图中(没有负权重也可以用,但是效率比狄克斯特拉算法低很多),搜索出源点到各个节点的最短路径
2、Bellman–Ford可以判断出图是否存在负环路,但存在负环路的情况下不支持计算出各个节点的最短路径。只需要在结束(节点数目-1)次遍历后,再执行一次遍历,若还可以更新数据则说明存在负环路
算法-贝尔曼-福特算法相关推荐
- JavaScript实现bellmanFord贝尔曼-福特算法(附完整源码)
JavaScript实现bellmanFord贝尔曼-福特算法 bellmanFord.js完整源代码 bellmanFord.js完整源代码 export default function bell ...
- C++实现bellman ford贝尔曼-福特算法(最短路径)(附完整源码)
C++实现bellman ford贝尔曼-福特算法 实现bellman ford贝尔曼-福特算法的完整源码(定义,实现,main函数测试) 实现bellman ford贝尔曼-福特算法的完整源码(定义 ...
- 算法系列——贝尔曼福特算法(Bellman-Ford)
本系列旨在用简单的人话讲解算法,尽可能避免晦涩的定义,读者可以短时间内理解算法原理及应用细节.我在努力! 本篇文章编程语言为Python,供参考. 贝尔曼福特算法(Bellman-Ford) 典型最短 ...
- 贝尔曼-福特算法(Bellman-Ford)最短路径问题
贝尔曼-福特算法(Bellman-Ford) 一.贝尔曼-福特算法(Bellman-Ford) 二.代码实现 一.贝尔曼-福特算法(Bellman-Ford) 贝尔曼-福特算法与迪科斯彻算法类似,都以 ...
- 了解贝尔曼·福特算法
文章目录 为什么在现实生活中会有负权重的边? 为什么我们要留意负权重? 贝尔曼·福特算法如何工作 贝尔曼·福特伪码 Bellman Ford vs Dijkstra C示例 贝尔曼·福特算法的复杂度 ...
- Python实现迪杰斯特拉算法和贝尔曼福特算法求解最短路径
文章目录 (一).题目 (二).导库 (三).绘制带权无向图 (四).获得最短路径 (四).实现最短路径高亮 (五).完整代码 (六).结果展示 关于Python数据分析在数学建模中的更多相关应用:P ...
- Bellman-Ford贝尔曼福特算法实现
作为一种单源最短路径算法,Bellman-Ford对于有向图和无向图都能适用,它还有一个Dijkstra算法无法具备的特点,那就是对含负权图的最短路径搜索. 每i轮对边的遍历之后,只要不存在负权回路, ...
- 算法:贝尔曼-福特算法
算法:贝尔曼-福特算法 1.简介 贝尔曼-福特算法(Bellman–Ford algorithm)是一个查找最短路径算法主要优点是支持负权重,但时间复杂度较高,还会有负权环的问题. 如果不需要权重应该 ...
- 算法/最短路径/Bellman-Ford贝尔曼福特算法
##问题描述 Dijkstra算法是处理单源最短路径的有效算法,但它局限于边的权值非负的情况,若图中出现权值为负的边,Dijkstra算法就会失效,求出的最短路径就可能是错的.这时候,就需要使用其他的 ...
最新文章
- 青龙面板node-onebot 教程
- Source Insight 格式化
- ubuntu 18.04设置系统自带系统截图快捷键
- sysbench 压测 mysql_sysbench压测
- 千灯腾碧人潮涌,蓬勃“雨花”气如虹
- VS Supercharger插件的破解
- C语言学习之输出“魔方阵”。所谓魔方阵是指这样的方阵,它的每一行、每一列和对角线之和均相等。
- android多屏应用程序,微软也尝试“多屏协同” Windows系统可以运行安卓程序
- ajax登录非空判断,email ajax传输数据去重和非空判断(示例代码)
- Maximum upload size exceede上传文件大小超出解决
- Java语言学习概述
- 基于matlab 的燃油喷雾图像处理方法,基于MATLAB的燃油喷雾图像处理方法.doc
- 字符串转换到double数组
- python消息队列celery_python异步任务神器celery
- WAV音频格式解析C代码
- T-SQL语言(二)
- MM模块采购收货的错误解决方案(2)
- An NVIDIA kernel module ‘nvidia-drm‘ appears to already be loaded in your kernel...
- AMI码及HDB3码的编译码程序设计
- 数列求和再求极限问题