每周一算法:负环判断

题目链接

负环

题目描述

给定一个 n n n 个点的有向图,请求出图中是否存在从顶点 1 1 1 出发能到达的负环。

负环的定义是:一条边权之和为负数的回路。

输入格式

本题单测试点有多组测试数据

输入的第一行是一个整数 T T T,表示测试数据的组数。对于每组数据的格式如下:

第一行有两个整数,分别表示图的点数 n n n 和接下来给出边信息的条数 m m m

接下来 m m m 行,每行三个整数 u , v , w u, v, w u,v,w

  • w ≥ 0 w \geq 0 w0,则表示存在一条从 u u u v v v 边权为 w w w 的边,还存在一条从 v v v u u u 边权为 w w w 的边。
  • w < 0 w < 0 w<0,则只表示存在一条从 u u u v v v 边权为 w w w 的边。

输出格式

对于每组数据,输出一行一个字符串,若所求负环存在,则输出 YES,否则输出 NO

样例 #1

样例输入 #1

2
3 4
1 2 2
1 3 4
2 3 1
3 1 -3
3 3
1 2 3
2 3 4
3 1 -8

样例输出 #1

NO
YES

提示

数据规模与约定

对于全部的测试点,保证:

  • 1 ≤ n ≤ 2 × 1 0 3 1 \leq n \leq 2 \times 10^3 1n2×103 1 ≤ m ≤ 3 × 1 0 3 1 \leq m \leq 3 \times 10^3 1m3×103
  • 1 ≤ u , v ≤ n 1 \leq u, v \leq n 1u,vn − 1 0 4 ≤ w ≤ 1 0 4 -10^4 \leq w \leq 10^4 104w104
  • 1 ≤ T ≤ 10 1 \leq T \leq 10 1T10
提示

请注意, m m m 不是图的边数。

算法思想

判断图中是否存在负环,需要先了解下面关于最短路的几个性质:

  • 对于边权为正的图,任意两个节点之间的最短路,不会经过重复的节点。
  • 对于边权为正的图,任意两个节点之间的最短路,不会经过重复的边。
  • 对于边权为正的图,任意两个节点之间的最短路,任意一条的节点数不会超过 n n n,边数不会超过 n − 1 n-1 n1

Bellman–Ford 算法

Bellman–Ford 算法是一种基于松弛(relax)操作的最短路算法,可以求出有负权的图的最短路,并可以对最短路不存在的情况进行判断。大名鼎鼎的「SPFA」,就是 Bellman–Ford算法的一种实现。

基本思想

Bellman–Ford算法所做的,就是不断尝试对图上每一条边进行松弛。每进行一轮循环,就对图上所有的边都尝试进行一次松弛操作,当一次循环中没有成功的松弛操作时,算法停止。

对于边 ( u , v ) (u,v) (u,v),Bellman–Ford算法中松弛操作对应下面的式子: d i s ( v ) = min ⁡ ( d i s ( v ) , d i s ( u ) + w ( u , v ) ) dis(v) = \min(dis(v), dis(u) + w(u, v)) dis(v)=min(dis(v),dis(u)+w(u,v))。尝试用 S → u → v S \to u \to v Suv(其中 S → u S \to u Su 的路径取最短路)这条路径去更新 v v v 点最短路的长度,如果这条路径更优,就进行更新。

每次循环的时间复杂度是 O ( m ) O(m) O(m),那么最多会循环多少次呢?

在最短路存在的情况下,由于一次松弛操作会使最短路的边数至少 + 1 +1 +1,而最短路的边数最多为 n − 1 n-1 n1,因此整个算法最多执行 n − 1 n-1 n1 轮松弛操作。故总时间复杂度为 O ( n m ) O(nm) O(nm)

但还有一种情况,如果从 S S S 点出发,抵达一个负环时,松弛操作会无休止地进行下去。对于最短路存在的图,松弛操作最多只会执行 n − 1 n-1 n1 轮,因此如果第 n n n 轮循环时仍然存在能松弛的边,说明从 S S S 点出发,能够抵达一个负环。

代码实现

struct Edge {int u, v, w;
};vector<Edge> edge;int dis[MAXN], u, v, w;
const int INF = 0x3f3f3f3f;
//节点数n,起点s
bool bellmanford(int n, int s) {memset(dis, 0x3f, sizeof(dis));dis[s] = 0;bool flag = false;  // 判断一轮循环过程中是否发生松弛操作for (int i = 1; i <= n; i++) {flag = false;for (int j = 0; j < edge.size(); j++) {u = edge[j].u, v = edge[j].v, w = edge[j].w;if (dis[u] == INF) continue;// 无穷大与常数加减仍然为无穷大// 因此最短路长度为 INF 的点引出的边不可能发生松弛操作if (dis[v] > dis[u] + w) {dis[v] = dis[u] + w;flag = true;}}// 没有可以松弛的边时就停止算法if (!flag) {break;}}// 第 n 轮循环仍然可以松弛时说明 s 点可以抵达一个负环return flag;
}

队列优化的Bellman–Ford

SPFA即 Shortest Path Faster Algorithm,即队列优化的Bellman–Ford。很多时候Bellman–Ford算法并不需要那么多无用的松弛操作, 只有上一次被松弛的结点,所连接的边,才有可能引起下一次的松弛操作。那么可以用队列来维护哪些结点可能会引起松弛操作,就能只访问必要的边了。

SPFA也可以用于判断 s s s点是否能抵达一个负环,只需记录最短路经过了多少条边,当经过了至少 n n n条边时,说明 s s s点可以抵达一个负环。

代码实现

struct edge {int v, w;
};vector<edge> e[maxn];
int dis[maxn], cnt[maxn], vis[maxn];
queue<int> q;bool spfa(int n, int s) {memset(dis, 0x3f, sizeof(dis));dis[s] = 0, vis[s] = 1;q.push(s);while (!q.empty()) {int u = q.front();q.pop(), vis[u] = 0;for (auto ed : e[u]) {int v = ed.v, w = ed.w;if (dis[v] > dis[u] + w) {dis[v] = dis[u] + w;cnt[v] = cnt[u] + 1;  // 记录最短路经过的边数if (cnt[v] >= n) return false;// 在不经过负环的情况下,最短路至多经过 n - 1 条边// 因此如果经过了多于 n 条边,一定说明经过了负环if (!vis[v]) q.push(v), vis[v] = 1;}}}return true;
}

虽然在大多数情况下SPFA跑得很快,但其最坏情况下的时间复杂度为 O ( n m ) O(nm) O(nm),将其卡到这个复杂度也是不难的,所以考试时要谨慎使用。在没有负权边时最好使用Dijkstra算法,在有负权边且题目中的图没有特殊性质时,若SPFA是标算的一部分,题目不应当给出Bellman–Ford算法无法通过的数据范围。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/826734.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《乱弹篇(30)厌战的杜诗》

时下地球村有一伙成天叫嚣着“打打杀杀”、鼓吹快快发动战争的狂人&#xff0c;他们视老百姓的生命如草芥&#xff0c;毫不珍惜。没有遭受过战火焚烧的人&#xff0c;也跟着成天吠叫“快开战吧”。然而中国唐朝大诗人却是个“厌战派”&#xff0c;他对战争的厌恶集中表现在诗《…

[系统安全] 五十七.恶意软件分析 (9)利用MS Defender实现恶意样本家族批量标注(含学术探讨)

您可能之前看到过我写的类似文章,为什么还要重复撰写呢?只是想更好地帮助初学者了解病毒逆向分析和系统安全,更加成体系且不破坏之前的系列。因此,我重新开设了这个专栏,准备系统整理和深入学习系统安全、逆向分析和恶意代码检测,“系统安全”系列文章会更加聚焦,更加系…

WebRTC的3A和SpeexDSP如何选择

SpeexDSP 是一个专门用于语音处理的开源库&#xff0c;它是从 Speex 项目中分离出来的。SpeexDSP 提供了多种音频处理功能&#xff0c;包括回声消除&#xff08;AEC&#xff09;、噪声抑制&#xff08;ANS&#xff09;、自动增益控制&#xff08;AGC&#xff09;以及声音的预处…

基于单目相机的标靶三维定位——编程实现

上一章内容中我们描述了基于单目相机实现标靶三维定位的原理,关键步骤为1)计算得到相机的内参和畸变系数;2)计算得到标靶角点的世界坐标和像素坐标;3)计算标靶坐标系到相机坐标系的变换矩阵。 第一点我们通过相机标定得到;第二点的核心功能我们可以借助cv::findChessboa…

放大器DC参数测试(1)

放大器DC参数测试(1) Hi,uu们,最近在忙啥呢?想好5.1,端午去哪里玩了吗? 咱们直接开始正题,放大器的DC参数还挺多,在Bench测试中,需要自动化测试,通常需要很多Relay去切换不同的配置去测量不同的参数,在这里瑞萨给出了测试参考电路.如图1所示. 图1:直流关键参数测试电路 Re…

近期分享学习心得4

1、带有多的条件的if的语句 逻辑 || 的简写 if (x true || x 2523 || x 小明) {}// 简化操作if ([true, 2523, 小明].includes(x)) {}2、查找两个数组的交集 var numOne [0, 2, 4, 6, 8, 8]; var numTwo [1, 2, 3, 4, 5, 6]; var cross [...new Set(numOne)].filter(item…

【树莓派】如何刷个系统给树莓派4B,如何ssh登陆到树莓派

文章目录 下载树莓派镜像下载烧写软件烧写编辑设置连接树莓派4B重启ssh查看树莓派IPssh远程连接问询、帮助 下载树莓派镜像 https://www.raspberrypi.com/software/operating-systems/#raspberry-pi-os-64-bit 下载烧写软件 https://www.raspberrypi.com/software/ 烧写 编辑…

python使用redis存储时序数据

import redisdef ts_demo():"""时序数据存储RedisTimeSeries测试"""# 连接到Redisr redis.Redis(hostlocalhost, password"xxxx", port63790, db0)r1 r.ts()# print(r1.get("ts_key"))# print(r.exists(ts_key))# # 清空键…

【网络安全 | 信息收集】JS文件信息收集工具LinkFinder安装使用教程

文章目录 前言安装教程使用教程 前言 JavaScript文件可能会泄露敏感信息&#xff0c;如注释中的机密信息、内部IP地址&#xff0c;以及包含未授权访问或其他漏洞的URL。手动检查这些信息效率低下&#xff0c;而该工具——LinkFinder&#xff0c;可用于自动收集JavaScript文件中…

c 哈希表

理解哈希表&#xff0c;就是先生成一 临时数组&#xff0c;用于存放全部待检测数的值&#xff0c;再创造一函数&#xff0c;关联待检测数与临时数组的每一元素的下标。 查询时根据关联函数用待检测数推算出临时函数的下标值&#xff0c;再读出此下标的元素值。这样就省去了遍历…

CefSharp.WinForms模拟登录

一、新建Web项目 {ViewData["Title"] "Home Page";Layout null; } <script src"~/lib/jquery/dist/jquery.min.js"></script> <script src"~/lib/jquery/dist/jquery.js"></script> <head><scrip…

otomegame游戏音频提取通用教程

otomegame游戏音频提取通用教程 文章目录 otomegame游戏音频提取通用教程一、otomegame游戏介绍二、游戏拆包与语料提取目标TTS语料积累最终目标&#xff1a; 三、游戏拆包简要介绍1&#xff0c;游戏资源提取关键词2&#xff0c;游戏拆包工具&#xff08;1&#xff09;游戏资源…

FairAdaBN论文速读

FairAdaBN: Mitigating Unfairness with Adaptive Batch Normalization and Its Application to Dermatological Disease Classification 摘要 深度学习在医疗研究和应用中变得越来越普遍&#xff0c;同时涉及敏感信息和关键诊断决策。研究人员观察到不同人口统计属性子组之间…

变频器基础原理

文章目录 0. 基本知识1.三相的电压之和为02.正弦交流相量的相量表示法(相量只是表示正弦量&#xff0c;而不等于正弦量 &#xff1b;只有正弦量才能用相量表示)引入相量表示法目的:一种正弦量的产生方式:正弦量的相量表示&#xff0c;使用欧拉公式表示复数 3.用复数表示正弦量&…

基于SpringBoot + Vue实现的医护人员排(值)班系统设计与实现+毕业论文+开题报告

项目介绍 本医护人员排班系统包括管理员&#xff0c;医护。 管理员功能有个人中心&#xff0c;医院信息管理&#xff0c;医护信息管理&#xff0c;医护类型管理&#xff0c;排班信息管理&#xff0c;排班类型管理&#xff0c;科室信息管理&#xff0c;投诉信息管理。 医护人员…

Swift-20-基础数据类型

数据定义 语法规则 先来看下下面的代码 import Cocoavar num1 "four" //a var num2: String "four" //b var num3 4 //c var num4: Int 4 //d上面的几行代码都能正常运行&#xff0c;其中a和b行等价&#xff0c;c和d行等价。区另就在于是否声…

学习记录693@java使用svnkit实战之上传文件到svn

前提 我是在linux通过yum install subversion 安装的svn&#xff0c;访问的协议是svn协议&#xff0c;也就是url是svn://ip/…的方式&#xff0c;网上几乎所有的文章在用svnkit的时候都是http协议访问svn服务器的。我模仿后都是报错的。 代码 <dependency><groupId…

AppWizard的软件开发GUI的使用记录

前言 这个软件是针对于EmWin6.0以上的这个软件在emWin的基础上又封装了一层,也只提供的API函数.基于消息事件为核心&#xff08;个人理解&#xff09;一些组件的之间的交互可以通过软件界面进行配置,比较方便本次是基于模拟器进行测试记录,观察api 按键和文本之间的关联 通过…

阿里巴巴fastjson实现复制

以下为真实案例&#xff0c;供日常开发使用 package com.somnus.json;import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.somnus.custom.domain.Area; import com.somnus.custom.domain.Employee; import com.somnus.custom.domain.Empl…

腾讯视频 2025届暑期实习 自然语言处理/LLM (已OC)

文章目录 写在前面一面 2024/3/28 晚上19:00-20:00二面 2024/4/9 下午16:30-17:50三面/HR面 2024/4/17 下午16:30-16:50 写在前面 学校情况&#xff1a;2本9硕&#xff0c;本硕都是计算机科班&#xff0c;但研究方向并不是NLP&#xff0c;而是图表示学习&#xff0c;也算是转行…