一、前言

在之前的学习中,我们学习了用Dijkstra算法求有向图的最短路问题Dijkstra算法求最短路博客。但是在Djkstra算法中,我们认为可以走的步骤是无限的,但是在日常问题中,我们需要解决有步数限制的最短路问题,这个时候,我们就需要学习一个新的算法来解决这个问题----Bellman_Ford算法。虽然看上去又是一个高大上的算法,但其实这个算法的实现也并不是什么太难的事情。而且,它还能处理边的长度为负数的情况。

二、Bellman_Ford算法介绍

由于是有步数限制和负数边存在,我们不能使用Djkstra算法,但是Bellman_Ford算法的实现和Djkstra算法在思路上还是差不多的。

首先,初始化距离:起点到起点的距离为0,到其它点的距离都为无限大(红字代表到起点的距离,蓝字代表边的长度)

Bellman_Ford算法首先需要枚举步数,然后更新第i步后每个点距离起点的最短长度。具体实现方法是两层for循环,第一层循环步数,而第二层循环枚举每一条边a------>b长为w,比较当前的dis[b]与dis[a]+w,更新最小值。但是这里要注意,我们每次需要用一个数组te[N]来存下dis[N]用来下一步的更新,因为在算法公式中“比较当前的dis[b]与dis[a]+w,更新最小值”的操作我们需要用到dis,但是在每一次循环中,dis是不断更改的,因此我们需要用te数组存下上一次变化后的结果。

1.如图。第一次循环步数后,走完第一步后图变为
dis={0,1e9,1e9,1e9,1e9};
te={0,1e9,1e9,1e9,1e9};

1e9>te[1]+2=2,dis[2]=2;
dis={0,2,1e9,1e9,1e9};

2.继续循环到走二步,图变为
dis={0,2,1e9,1e9,1e9};
te={0,2,1e9,1e9,1e9};

1e9>te[2]-2=0;dis[3]=0
1e9>te[2]+1=3;dis[4]=3
dis={0,2,0,3,1e9};

3.走三步
dis={0,2,0,3,1e9};
te={0,2,0,3,1e9};

3>te[3]+2=2;dis[4]=2
1e9>te[4]+1=4;dis[5]=4
dis={0,2,0,2,4};

4.走四步
dis={0,2,0,2,4};
te={0,2,0,2,4};

4>te[4]+1=3;dis[5]=3
dis={0,2,0,2,5};

在上面的有向图中,最长能走4步,然后在上面的图中我们就枚举了步数为1~4步时的到各个点的最短的距离。

二、Bellman_Ford代码实现

例题链接:Acwing 有边数限制的最短路

给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环, 边权可能为负数。请你求出从 1 号点到 n 号点的最多经过 k 条边的最短距离,如果无法从 1 号点走到 n 号点,输出 impossible。注意:图中可能 存在负权回路 。输入格式
第一行包含三个整数 n,m,k。接下来 m 行,每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。输出格式
输出一个整数,表示从 1 号点到 n 号点的最多经过 k 条边的最短距离。如果不存在满足条件的路径,则输出 impossible。数据范围
1≤n,k≤500,
1≤m≤10000,
任意边长的绝对值不超过 10000。输入样例:
3 3 1
1 2 1
2 3 1
1 3 3
输出样例:
3

这一道题就是Bellman_Ford算法的板子题,是需要看懂的,不过这里我们并不需要用到我们存图常用的链式前向星存图,因为我们只要遍历了所有的边就可以了,并没有要求要怎样遍历完所有的边。

看懂代码前你需要知道的
1.作者重写的mem函数“#define mem(a,b) memset(a,b,sizeof(a))”
2.memcpy函数

//#pragma GCC optimize(2)
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#include<ctime>
#include<cstring>
#include<list>
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef  pair<int, int> PII;
const int N = 1e6 + 7;int n, m, k;
int dis[N], te[N];
struct edge  //边
{int f, t, w;   //定义边的起点,终点,长度
};edge ed[N];int Bellman_Ford()
{mem(dis, 0x3f);  //初始化距离为一个很大的数dis[1] = 0;  //起点到起点的距离为0for (int i = 0; i < k; i++)  //遍历步数{memcpy(te, dis, sizeof dis);   //复制数组函数for (int j = 1; j <= m; j++)   //遍历每一条边{int f = ed[j].f, t = ed[j].t, w = ed[j].w;dis[t] = min(dis[t], te[f] + w);}}return dis[n];  //返回最后的答案
}void solve()
{cin >> n >> m >> k;for (int i = 1; i <= m; i++)  //输入每一条边{int a, b, c;cin >> a >> b >> c;ed[i] = { a,b,c };}int t=Bellman_Ford();  //用一个数来接收最后的答案if (t > INF / 2)     //如果这个数很大代表到不了,至于为什么不是">INF"在下方解释cout << "impossible" << endl;else   //输出答案即可cout <<t << endl;
}int main()
{//std::ios::sync_with_stdio(false);//cin.tie(0), cout.tie(0);solve();return 0;
}

解释为什么不是">INF"而是“>INF/2”:由于题目中可能会有负数边存在,在公式"dis[t] = min(dis[t], te[f] + w);“中,如果dis[t]=1e9,w为-2,那么我们发现dis[t]被更新成了1e9-2,但是1e9-2实际上并不是代表路的长度为1e9-2,而是代表不能到达,根据题目中数据范围,我们可以发现,我们虽然不能写成”>INF",但是“>INF/2”是可以判断是否能到达终点的。

作者:Avalon Demerzel,喜欢我的博客就点个赞吧,更多图论与数据结构知识点请见作者专栏《图论与数据结构》

【图论】Bellman_Ford算法求有步数限制的最短路(图文详解)相关推荐

  1. 图文详解两种算法:深度优先遍历(DFS)和广度优先遍历(BFS)

    图文详解两种算法:深度优先遍历(DFS)和广度优先遍历(BFS) 阅读本文前,请确保你已经掌握了递归.栈和队列的基本知识,如想掌握搜索的代码实现,请确保你能够用代码实现栈和队列的基本操作. 深度优先遍 ...

  2. Dijkstra算法图文详解和C++代码

    文章目录 1 Dijkstra算法基本原理 2 算法过程图解1(有向图) 3 算法过程图解2(无向图) 4 C++代码 4.1 案例1代码 4.2 案例2邻接矩阵定义 4.3 案例2代码Dijkstr ...

  3. php 去重_php求两数组交集的四种方法详解

    题目:给定两个数组,编写一个函数来计算它们的交集. 示例 1: 输入: nums1 = [1,2,2,1],nums2 = [2,2] 输出: [2] 示例 2: 输入: nums1 = [4,9,5 ...

  4. prim求最短路径C语言,[图论]Prim算法求最小支撑树和最短路径

    这个是以前所学,现在总结成博文一篇. 对于图论中的求解最小支撑树问题和最短路径问题都有比较经典的算法,比如最小支撑树可以采用"破圈法",求解最短路径可以用"Dijkstr ...

  5. Bellman_Ford算法(求一个点到任意一点的最短距离)

    单源最短路问题是固定一个起点,求它到任意一点最短路的问题. 记从起点出发到顶点 i 的最短距离为d[i],则有以下等式成立 d[i]=min{d[j]+(从j到 i 的边的权值) 看代码 #inclu ...

  6. c++数据结构中 顺序队列的队首队尾_数据结构与算法—队列图文详解

    前言 栈和队列是一对好兄弟,前面我们介绍过数据结构与算法-栈详解,那么栈的机制相对简单,后入先出,就像进入一个狭小的山洞,山洞只有一个出口,只能后进先出(在外面的先出去).而队列就好比是一个隧道,后面 ...

  7. c算法题中各种输入和输出方法技巧详解!

    文章目录 引言 导入io库 输入 各种输入方法 `scanf` 格式说明符 基本示例 读入整数 读入其他类型的数字 读入单个字符 读入字符串 扫描字符集合 `getchar()` `gets()` ` ...

  8. 机器学习算法(二十五):KD树详解及KD树最近邻算法

    目录 1 KD树 1.1 什么是KD树 1.2 KD树的构建 1.3 KD树的插入 1.4 KD树的删除 1.5 KD树的最近邻搜索算法 1.5.1 举例:查询点(2.1,3.1) 1.5.2 举例: ...

  9. KMP算法图文详解(为什么是next[0]=-1、next[j]=k和k=next[k])

    文章目录 一:KMP算法解决的问题 二:详解KMP (1)暴力匹配的缺点 (2)最长相同前缀和后缀 (3)究竟怎么回溯 (3)next数组 (4)求解next数组 A:next[0]=-1 B:nex ...

  10. 图搜索算法UCS(一致代价搜索)通俗易懂图示详解

    一致代价搜索实际上是在BFS(广度优先搜索算法)的基础上进行扩展的,我们在上一篇博客图搜索算法BFS和DFS通俗易懂图示详解中提到,BFS是基于队列数据结构的,既然UCS是BFS的扩展,那么UCS一定 ...

最新文章

  1. Java线程池实现原理及其在美团业务中的实践
  2. 批处理if 命令示例详解
  3. 浅谈计算机程序设计语言,探讨计算机程序设计语言教学
  4. 搭建xxpay支付平台
  5. java中对象排序_java中 对象的排序
  6. 《Linux》美轮美奂的Arch, 详解Arch虚拟机安装
  7. 【IMU】BMI160 Driver分析及使用
  8. 卡贴机变无锁教程_iphone卡贴机ICCID激活去掉卡贴变成无锁机的教程及原理
  9. php excel自适应列宽,PHPExcel自动调整列宽
  10. ie浏览器点击打印没反应_解决在IE菜单中点击打印无反应
  11. 微信小程序企业号注册
  12. java编写打砖块小游戏
  13. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
  14. 中国机器视觉产业业发展战略研究及投资方向分析报告2022-2027年
  15. PC版京东炸年兽活动一键做任务 全民自动炸年兽最新版1.1
  16. 【java8】LocalDateTime、LocalDate与LocalTime的基本使用
  17. java web二手书店,基于jsp的二手书交易-JavaEE实现二手书交易 - java项目源码
  18. 《阿信》讲述了日本着名的百货连锁企业八佰伴创始人艰苦的过程
  19. 又一所985大学改考408!中国海洋大学计算机专硕
  20. SAP MM模块一些表

热门文章

  1. 【Foreign】Weed [线段树]
  2. 今天遇到的一个诡异的core和解决 std::sort
  3. 织梦内容模型管理(人才招聘)
  4. Linux C enum
  5. 新浪微博开放平台链接耗尽的情况分析
  6. install mysql with source code
  7. 三层结构对多语言的支持
  8. Mercurial:Hg缓存更改的文件和打patch
  9. 29.FFmpeg+OpenGLES+OpenSLES播放器实现(三.FFmpeg配置和编译脚本)
  10. WPF中的Application类。