Acwing Bellman-Ford SPFA
1. Bellman-Ford
该算法适用于有负权边的情况,注意:如果有负权环的话,最短路就不一定存在了。时间复杂度 O ( m n ) . O(mn). O(mn).该算法可以求出来图中是否存在负权回路,但求解负权回路,通常用SPFA算法,而不用Bell-Ford算法,因为前者的时间复杂度更低。
Bellman-ford不要求用邻接表或者邻接矩阵存储边,为简化操作,可以定义一个结构体,存储a,b,w。表示存在一条边a点指向b点,权重为w。则遍历所有边时,只要遍历全部的结构体数组即可
主要步骤:
- 循环n次:循环的次数的含义:假设循环了k次则表示:从起点经过不超过k条边,走到某个点的最短距离
- 每次循环,遍历图中的所有的边。对每条边(a,b,w),(指的是从a点到b点,权值是w的一条边)更新d[b] = min(d[b],d[a]+w)。该操作称为松弛操作。
- 该算法能够保证,在循环n次后,对所有的边(a,b,w),都满足d[b] <= d[a] + w。这个不等式被称为三角不等式。
ACwing 853. 有边数限制的最短路
实现思路:
- 利用上述的Bellman-ford算法
- 依旧定义一个距离数组dist,初始化未正无穷(0x3f3f3f3f)。注意最后判断到n号节点是否有路径不是直接判断dist[n] == 0x3f3f3f3f,因为存在负权边,可能更新的时候会存在dist[n] = 0x3f3f3f3f - c,即无穷大加上一个负数,仍为无穷大但数值还是改变了,所以最后有路径的判断改为dist[n] > 0x3f3f3f3f / 2.
- 本题要求1号到n号点不超过k条边的最短距离,则循环k次来寻找最短路;
- 每次再遍历m条边,判断加入当前点后,各店点到起点的距离是否变小,若变小则更新距离;
- 注意:该距离更新时可能会导致参与的边的数量大于k,因此应在每次遍历前设置一个备份数组backup,记录在k次遍历中,本次遍历的上一次的距离数组状态,在该次遍历中对每条边的距离数组更新时采用备份数组,确保本次更新范围在当前的边数限制内。
具体实现代码:`
#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;const int N = 510, M = 10010;int n, m, k; // n: 顶点数, m: 边数, k: 最多使用的边数
int dist[N], backup[N]; // dist: 存储当前节点的最短距离,backup: 每轮备份上一轮的最短距离// 定义一个结构体存储边的信息
struct Edge {int a, b, w; // a: 起点, b: 终点, w: 边的权重
} edges[M]; // 存储所有的边,最多 M 条// Bellman-Ford 算法的核心函数,返回 1 到 n 的最短距离
int bellman_ford() {// 初始化距离数组,将所有点的距离设置为一个非常大的值(无穷大)memset(dist, 0x3f, sizeof dist);dist[1] = 0; // 源点(起点)1到自己的距离为 0// Bellman-Ford 算法允许最多使用 k 条边来放松所有边for (int i = 0; i < k; i++) { // 执行 k 轮松弛操作memcpy(backup, dist, sizeof dist); // 将当前距离备份// 遍历每条边,尝试更新目标顶点的最短距离for (int j = 0; j < m; j++) {int a = edges[j].a, b = edges[j].b, w = edges[j].w; // 获取边的起点,终点和权重dist[b] = min(dist[b], backup[a] + w); // 更新顶点 b 的距离}}// 如果最终 dist[n] 的值仍然非常大,说明无法在 k 条边以内到达顶点 nif (dist[n] > 0x3f3f3f3f / 2) return -1; // 0x3f3f3f3f 是表示无穷大的近似值return dist[n]; // 返回最短路径距离
}int main() {cin >> n >> m >> k; // 读取顶点数 n, 边数 m 和最多可用边数 k// 读取每条边的起点、终点和权重,并存入 edges 数组for (int i = 0; i < m; i++) {int a, b, w;cin >> a >> b >> w;edges[i] = {a, b, w};}// 调用 bellman_ford 函数计算最短路径int t = bellman_ford();// 如果 t 返回 -1 且 dist[n] 不是 -1(没有负权环),输出 "impossible"if (t == -1 && dist[n] != -1) puts("impossible"); else cout << t << endl; // 否则输出最短路径的距离return 0;
}
2.SPFA
-
若要使用SPFA算法,一定要求图中不能有负权回路。只要图中没有负权回路,都可以用SPFA,即也可以求解正权边的题,这个算法的限制是比较小的。时间复杂度一般为 O ( m ) , O(m), O(m),最差为 O ( m n ) . O(mn). O(mn).在一些情况下可以代替Dijkstra算法
-
SPFA其实是对Bellman-Ford的一种优化,相比Bellman-Ford判环的时间复杂度也更低。 它优化的是这一步:d[b] =
min (d[b],d[a] + w) -
我们观察可以发现,只有当d[a]变小了,在下一轮循环中以a为起点的点(或者说a的出边)就会更新,即下一轮循环必定更新d[b]。
-
考虑用一个队列queue,来存放距离变小的节点(当图中存在负权回路时,队列永远都不会为空,因为总是存在某个点,在一次松弛操作后,距离变小)。
具体实现代码(详解版):
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>using namespace std;const int N = 100010;int e[N], ne[N], idx, w[N], h[N]; // e: 邻接点, ne: 下一条边的索引,
//idx: 当前边的索引, w: 边的权重, h: 头节点int dist[N]; // 存储从起点 1 到每个节点的最短距离
int n, m;
bool s[N]; // 记录节点是否在队列中,避免重复入队// 添加一条从 a 到 b 的边,权重为 c 的边
void add(int a, int b, int c) {e[idx] = b; // 终点 bne[idx] = h[a]; // 将边 idx 加到节点 a 的邻接表中w[idx] = c; // 边的权重h[a] = idx++; // 更新节点 a 的头指针,指向新加的边
}// SPFA 算法求解最短路径
int spfa() {memset(dist, 0x3f, sizeof dist); // 初始化距离为无穷大dist[1] = 0; // 起点 1 到自己的距离为 0queue<int> q; // 定义队列用于处理节点q.push(1); // 将起点 1 入队s[1] = true; // 标记起点 1 已入队// 队列不为空时进行循环while (q.size()) {auto t = q.front(); // 取出队首节点q.pop(); // 弹出队首节点s[t] = false; // 标记节点 t 不在队列中// 遍历节点 t 的所有邻接边for (int i = h[t]; i != -1; i = ne[i]) {int j = e[i]; // 获取节点 t 的邻接点 j// 如果从节点 t 到 j 的路径更短,则更新 j 的距离if (dist[j] > dist[t] + w[i]) {dist[j] = dist[t] + w[i];// 如果节点 j 不在队列中,则将其加入队列if (!s[j]) {s[j] = true; // 标记节点 j 已入队q.push(j); // 节点 j 入队}}}}// 如果终点 n 的距离仍然为无穷大,表示无法到达,返回 -1if (dist[n] > 0x3f3f3f3f / 2) return -1;else return dist[n]; // 否则返回最短距离
}int main() {cin >> n >> m; // 输入节点数 n 和边数 mmemset(h, -1, sizeof h); // 初始化头节点数组为 -1,表示没有边// 读取每条边的信息,并调用 add 函数将其加入邻接表while (m--) {int a, b, w;cin >> a >> b >> w;add(a, b, w);}// 调用 spfa 函数计算最短路径int t = spfa();// 如果最短距离为 -1,且终点距离不为 -1,则输出 "impossible"if (t == -1 && dist[n] != -1) puts("impossible");else cout << t << endl; // 否则输出最短路径的距离return 0;
}
相关文章:

Acwing Bellman-Ford SPFA
1. Bellman-Ford 该算法适用于有负权边的情况,注意:如果有负权环的话,最短路就不一定存在了。时间复杂度 O ( m n ) . O(mn). O(mn).该算法可以求出来图中是否存在负权回路,但求解负权回路,通常用SPFA算法,…...

我能禁止使用某协议的ip禁止访问我的资源吗
是的,你可以禁止使用某个协议的IP地址访问你的资源。这种操作通常涉及网络防火墙、服务器配置或应用程序设置,具体方法取决于你的网络环境和使用的技术。以下是一些常见的实现方法: 1. 使用防火墙 大多数防火墙(硬件或软件&…...

快速理解TCP协议(二)——TCP协议中的拥塞控制机制详解
在计算机网络中,TCP(传输控制协议)是一种广泛使用的面向连接的、可靠的、基于字节流的传输层通信协议。TCP协议通过一系列复杂的机制来确保数据的可靠传输,其中拥塞控制是至关重要的一环。本文将深入探讨TCP协议中的拥塞控制机制&…...

Linux:debug: systemtap: ubacktrace
https://docs.huihoo.com/systemtap/sourceware.org/systemtap/SystemTap_Beginners_Guide/ustack.html 这个函数可以帮助将user level的backtrace打印出来。 stap -d /bin/ls --ldd \ -e probe process("ls").function("xmalloc") {print_usyms(ubacktra…...

使用AI进行需求分析的案例研究
生成式 AI 的潜在应用场景似乎无穷无尽。虽然这令人兴奋,但也可能让人不知所措。因此,团队在使用这项技术时需要有明确的目标:关键是要明确生成式 AI 在团队工作中能产生哪些实质性影响。 在软件工程中,一个引人注目的应用场景是…...

Python内置的re库
Python内置的re库是专门用于处理正则表达式的标准库。它提供了一系列函数和类,使得在Python程序中可以使用正则表达式进行字符串的搜索、替换、分割等操作。re库的使用非常广泛,几乎任何需要复杂文本处理的场景都可以用到它。 主要函数 1、complie函数…...

毕业设计选题:基于ssm+vue+uniapp的面向企事业单位的项目申报小程序
开发语言:Java框架:ssmuniappJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:M…...

jQuery 简介⑤属性操作
九、属性操作 jQuery的属性操作方法一览表 $("selector").val(); // 获取第一个匹配元素的value值(一般用于表单控("selector").val("Hello"); // 设置所有匹配元素的value值为"Hello" $("selector").html();// 获取第一个…...

[Linux] Linux操作系统 进程的状态
标题:[Linux] Linux操作系统 进程的状态 个人主页:水墨不写bug (图片来源于网络) 目录 一、前置概念的理解 1.并行和并发 2.时间片 3.进程间具有独立性 4.等待的本质 正文开始: 在校的时候,你一定学过《…...

深入解析Python 中的 sortedcontainers 库:高效的排序数据结构
在日常的 Python 编程中,列表(list)、集合(set)和字典(dict)是常用的数据结构。然而,在某些特定的场景下,我们需要对数据进行排序,并且希望在插入、删除或访问…...

什么是服务器日志,日志有什么作用?
前言 服务器日志是指服务器等电脑设备或软件的运作记录。这些日志记录了服务器接收客户端处理请求的过程以及服务器对这些请求的处理结果。服务器日志对于排查和解决计算机系统和网络应用中的问题至关重要,因为它们包含了用于调试问题的消息、服务器状态以及其他…...

Codeforces Round 971 (Div. 4)A-G1题解
Codeforces Round 971 (Div. 4) A 就是b - a #include <bits/stdc.h> #define int long longusing namespace std;void solve() {int a, b;cin >> a >> b;cout << b - a << endl; }signed main() {ios::sync_with_stdio(false);cin.tie(0);co…...

QT----基于QML的计时器
赶上了实习的末班车,现在在做QML开发,第一天的学习成果,一个计时器.逻辑挺简单的,纯QML实现,代码在仓库,可以对比文档和提交记录学习起来更清晰 QT-Timer 学习使用c的listmodel 学习使用了如何用c的listmodel来存储数据. 新建一个TImeListModel类继承自QAbstractListModel c…...

Stable Diffusion的高分辨率修复(Hires.fix)
Stable Diffusion的高分辨率修复(Hires.fix)是一项重要的功能,它旨在提高生成图像的分辨率和细节,从而使画面变得更加清晰和精细。以下是关于Stable Diffusion高分辨率修复(Hires.fix)的详细解释࿱…...

智慧体育馆可视化:实时监控与智能管理
利用图扑可视化技术实现对体育馆的实时监控和数据分析,提升运营效率、观众体验和安全管理水平,打造智能化场馆环境。...

【NLP】基于“检测器-纠错器”中文文本纠错框架
前言 许多方法将中文拼写纠正(检测和纠正给定中文句子中的错误字符)视为序列标注任务,并在句子对上进行微调。一些方法使用错误检测器作为初步任务,然后将检测结果用于辅助后续的错误纠正过程。然而,现有方法在使用检…...

vue 中加载 Mapbox GL JS Examples
Mapbox GL JS 示例 1. Mapbox GL JS的基础使用2. style 的使用2.1. 切换 style2.2. 配置一个第三方 style (添加一个Layer)2.3. 配置一个带有 slot 的 style2.4. 创建一个自定义 style 的 layer 类实现 WebGL 内容2.5. 添加Marker2.6. 添加 geojson 格式…...

Vue3 中组件传递 + css 变量的组合
文章目录 需求效果如下图所示代码逻辑代码参考 需求 开发一个箭头组件,根据父组件传递的 props 来修改 css 的颜色 效果如下图所示 代码逻辑 代码 父组件: <Arrow color"red" />子组件: <template><div class&…...

秋分之际,又搭建了一款微信记账本小程序
在这个金色的季节里,每一粒粮食都蕴含着生命的奇迹,每一片叶子都在诉说着成长的故事。秋分之际,又搭建了一款微信记账本小程序。 产品概述 微信记账本小程序是一款便捷的个人财务管理工具,旨在帮助用户轻松记录、管理和分析日常…...

聚合函数count 和 group by
count函数: count(列名) SELECT COUNT(sid) FROM grade 统计列中所有的数值个数,会忽略null值。 count(*)和count(1) SELECT COUNT(*) FROM grade SELECT COUNT(1) FROM grade 统…...

Vue的工程化和element快速入门
vue项目的创建: vue项目的启动方式: vue项目开发流程: 代码示例: <!-- <script>//写数据export default{data(){return{msg: 上海}}} </script> --><script setup>import {ref} from vue;//调用ref函数&…...

【Kubernetes】常见面试题汇总(三十一)
目录 83.简述你知道的 K8s 中几种 Controller 控制器并详述其工作原理。简述 ingress-controller 的工作机制。 特别说明: 题目 1-68 属于【Kubernetes】的常规概念题,即 “ 汇总(一)~(二十二)” 。 …...

在 Windows 上安装和配置 NVIDIA 驱动程序、CUDA、cuDNN 和 TensorRT
在 Windows 上安装和配置 NVIDIA 驱动程序、CUDA、cuDNN 和 TensorRT 1. 安装 NVIDIA 图形驱动程序2. 安装 CUDA Toolkit3. 安装 cuDNN4.安装 TensorRT5. 常见问题1. 安装 NVIDIA 图形驱动程序 首先需要安装兼容 CUDA 的 NVIDIA 驱动程序。 下载最新驱动: 访问 NVIDIA 官网,…...

京准电钟:NTP网络校时服务器助力校园体育场馆
京准电钟:NTP网络校时服务器助力校园体育场馆 京准电钟:NTP网络校时服务器助力校园体育场馆 体育场馆数字时钟系统可为观众及工作人员提供标准时间信息,为计算机及其他系统提供标准时间源,为协调场馆各业务系统与各部门的工作提供…...

9.25度小满一面
1.map的底层 2.unorder_map哈希表有自己实现过吗?哈希冲突 3.poll和epoll和select的优缺点、 4.线程同步机制是用来做什么的? 5.五子棋项目问题-- 算法题: 6.LeetCode.重排链表 给定一个单链表 L 的头节点 head ,单链表 L 表示为: L0…...

mysql批量修改表前缀
现有表前缀xh,批量修改为fax_需要怎么做 SELECTCONCAT(ALTER TABLE ,table_name, RENAME TO fax_,substring(table_name, 3),;) FROMinformation_schema. TABLES WHEREtable_name LIKE xh_%; 运行之后可以但是生成了一批修改表明的命令 此时批量复制执行就可实现批量修改表前…...

算法复杂度
1. 数据结构前⾔ 1.1数据结构 数据结构是计算机存储数据,组织数据的方式,指相互之间存在⼀种或多种特定关系的数 据元素的集合。常见的数据结构有线性表,树,图,哈希等。 1.2 算法 算法是一种计算过程,输…...

vue到出excel
安装 npm install exceljs npm install file-saver<template><button click"dade66">导出 66</button> </template><script> import ExcelJS from exceljs; import { saveAs } from file-saver;export default {data() {return {data…...

【延时队列的实现方式】
文章目录 延时队列JDK自带的延时队列实现Redis实现延迟队列RabbitMQ 延时队列 延时队列 延时队列是一种特殊类型的队列,它允许元素在特定时间间隔后才能被处理。这种队列在处理具有延迟需求的任务时非常有用,例如定时任务、事件驱动系统等 延时队列在项…...

Fyne ( go跨平台GUI )中文文档- 扩展Fyne (七)
本文档注意参考官网(developer.fyne.io/) 编写, 只保留基本用法 go代码展示为Go 1.16 及更高版本, ide为goland2021.2 这是一个系列文章: Fyne ( go跨平台GUI )中文文档-入门(一)-CSDN博客 Fyne ( go跨平台GUI )中文文档-Fyne总览(二)-CSDN博客 Fyne ( go跨平台GUI…...