P3385 【模板】负环 - SPFA模板
文章作者:gyro永不抽风
发布时间:2020年09月19日 - 23:09
最后更新:2020年09月19日 - 23:09
许可协议: 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 转载请保留原文链接及作者!
关于SPFA
SPFA原理
还是根据图论基本方程进行松弛操作,当无法继续松弛的时候,其实就已经达到了最优化,求出了单源最短路了。
为什么SPFA死了
因为数据很好卡。因为SPFA用的是双端队列,所以对于一些精心构造的图来说,复杂度其实是可以退化到$O(mn)$的。
为什么SPFA死了还要用
- 因为可以求负环
- 因为可以求带有负权边的最短路
SPFA和Dijkstra的区别
- Dijkstra+heap是用小根堆,每次取出$\text {dis}$最小的点,来更新距离,那么这个点来说,最小距离就是当前的d。
- SPFA是用双端队列,每次取出队头,来更新距离,它之后可能还会入队。它是一种动态逼近法,因为每次松弛距离都会减小,所以松弛一定会有结束的。如果一个点入队超过$n$次就是存在负环。
- 如果是稠密图,Dijkstra + Heap比SPFA快。稀疏图则SPFA更快。SPFA可以有SLF和LLL两种优化,SLF就是$\text {dis}$比队头小就插入队头,否则插入队尾。
- Dijkstra和Prim也很相似,它们的区别主要是d的含义,前者是到s的临时最短距离,后者是到树的临时最短距离,相同点是,每次找d最小的更新其它点的距离。
如何用SPFA判断负环
我们现在来思考一个问题:如果一张图上有$n$个点,那如果一条路径上有超过$n$个点会怎么样?
根据容斥原理,我们必定可以在路径上找到两个相同的点。换句话说,从一个点出发,又回到了这个点。然而整个过程确实求最短路的过程,路程$\text {dis}$不断在优化,所以这个环一定是负环(即路径和为负数)。而一条路径上有超过$n$个点,等价于一条路径有不少于$n$条边。而判断路径有多少条边其实非常容易,我们只需要在做松弛操作的时候更新记录路径条数的$\text {cnt}$数组就可以了:
$$ \text {dis}[u] + g[e].w < \text {dis}[v] \Rightarrow \text {cnt} [v] = \text {cnt} [u] + 1 $$
题目
题目描述
给定一个 个点的有向图,请求出图中是否存在从顶点 出发能到达的负环。
负环的定义是:一条边权之和为负数的回路。
输入格式
本题单测试点有多组测试数据。
输入的第一行是一个整数 ,表示测试数据的组数。对于每组数据的格式如下:
第一行有两个整数,分别表示图的点数 和接下来给出边信息的条数 。
接下来 行,每行三个整数 。
- 若 ,则表示存在一条从 至 边权为 的边,还存在一条从 至 边权为 的边。
- 若 ,则只表示存在一条从 至 边权为 的边。
输出格式
对于每组数据,输出一行一个字符串,若所求负环存在,则输出 YES
,否则输出 NO
。
输入输出样例
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
NO YES
说明/提示
数据规模与约定
对于全部的测试点,保证:
- ,。
- ,。
- 。
提示
请注意, 不是图的边数。
代码
1 |
|