当前位置: 首页 > ai >正文

Dijkstra?spfa?SPstra?

带负权的无负环最短路问题

对于一张有负边权的图,普通 Dijkstra 就不能用了,比如:
在这里插入图片描述
正常的 Dijkstra 扩散的节点依次为 1,3,2,41,3,2,41,3,2,4
这时候可以发现,当点 222 扩散的时候,原本达到点 333 的路径长度是 111,路径 1⟶2⟶31\longrightarrow2\longrightarrow3123 的权值之和为 −2-22,明显更短,这个时候点111 到点 333 的路径长度就会被更新为 −2-22,但是,点 333 在点 222 之前已经被扩散过,不会在进行第二次扩散。此时,点 111 到点 444 的路径长度依旧是 1+2=31+2=31+2=3

这里说明了 Dijkstra 的一个缺陷,贪心思路会考虑不到后续的负数。

那么,我们可以对 Dijkstra 做一个改动,解决现在遇到的问题。
上述的问题发生的根源就是 visvisvis 数组,在当前点找到更优值的时 visvisvis 数组不会改变,就导致了上图中点 444 没有被更新,所以我们在找到更优值时就再给当前点一个机会。

if(dis[y]>dis[x]+z){vis[y]=0;dis[y]=dis[x]+z;
}

这样可以很好地解决上图中出现的问题,但是判断负环还是需要 SPFA
那么,我们将上述的改动版 Dijkstra 命名为SPstra
在这里插入图片描述

带负环的最短路问题

这个时候就可以考虑用到 SPFA。
SPFA 与 Dijkstra 的不同点:

入队条件

Dijkstra 的遍历概念是:扩散
而 SPFA 的遍历概念是:挑选
SPFA 的标记表示的是“是否在队列中”,也就是说有没有看过这个元素值更新后对相连点的影响。
如果没有在队列中,并且还找到了当前点更优的方案,那么当前点就该入队上班了。(可以借助文章最顶上的图来理解)。

出队标记

出队后,元素就不在队列中了,标记取消。

负环判断

负环是什么?
负环就是一个有向图中的环,并且对这个环遍历一圈得到的权值总和为负,那么这个时候就可以一直绕着这个环转圈圈,使权值总和越来越小。
我们假设:一张有 nnn 个点的有向图中有这样一个点 xxx,这个点十分有魅力,图中其余的 n−1n-1n1 个点都有一条边连向这个点。

再极端一点,这其余的 n−1n-1n1 个点按照被遍历到的顺序依次对点 xxx 有更优贡献。
那么,这个点就会被入队 n−1n-1n1 次,这个时候还没有出现负环。
但是,如果这个点再被入队一次,入队次数达到了 nnn 次,就一定有一个点(暂且称为点 yyy)连接点 xxx 的这条路径被遍历了两次,这个时候就有了负环,因为点 xxx 在被点 yyy 连接的情况下还有一条负数边权和的路径连接着点 yyy

SPFA 可否使用优先队列优化

其实使用优先队列优化的 SPFA 就是前面的 “SPstra” 加上一个负环判断。

对于这个问题,答案是:能,但是很极端。

SPFA 优先队列优化的适用场景

对于正边权居多的图,可以使用优先队列优化,这样可以使效率接近 Dijkstra 的 O(Nlog⁡N)O(N\log N)O(NlogN)

普通 SPFA 的适用场景

对于负边权居多的图,其实普通队列和优先队列的遍历次数都是差不多的,只是顺序变了,而且优先队列还多了一个 O(log⁡N)O(\log N)O(logN),效率还不如普通队列。

总结

考试或者比赛时,题目的数据我们无从得知。
但我们知道的是,造数据的人们都是阴险狡诈忠恳善良的,我们可以猜疑相信他们。

http://www.xdnf.cn/news/17212.html

相关文章:

  • 【Rust】多级目录模块化集成测试——以Cucumber为例
  • 深入探索 PDF 数据提取:PyMuPDF 与 pdfplumber 的对比与实战
  • PCB焊盘脱落的补救办法与猎板制造优势解析
  • 五种IO模型 阻塞IO 多路转接之select 多路转接之poll
  • AI学习笔记三十五:实时传输视频
  • python应用GRPC || consul 服务注册发现
  • GraphRAG 入门教程:从原理到实战
  • 碰一碰NFC开发写好评php语言源码
  • day21|学习前端vue3框架和ts语言
  • 什么是SpringBoot
  • Spring事务失效场景?
  • TCP粘包问题详解与解决方案
  • 使用SETNX实现分布式锁
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘spacy’问题
  • 【C#补全计划:类和对象(九)】接口
  • 嵌入式开发硬件——单片机
  • QtC++ 中使用 qtwebsocket 开源库实现基于websocket的本地服务开发详解
  • Java中接口与抽象类
  • 【MATLAB】(十)符号运算
  • idea开发工具中git如何忽略编译文件build、gradle的文件?
  • 为什么 `source ~/.bashrc` 在 systemd 或 crontab 中不生效
  • 安卓开发:网络状态监听封装的奥秘
  • vLLM:彻底改变大型语言模型推理延迟和吞吐量
  • 【Apache Olingo】全面深入分析报告-OData
  • count(0),count(*),count(1),count(列)有什么区别?
  • Caffeine 三种过期策略详解
  • java - 深拷贝 浅拷贝
  • 大模型2位量化原理解析
  • 【线性代数】5特征值和特征向量
  • “认知裂缝边缘”地带