一、声明

在下面的描述中,未说明的情况下,\(N\) 是顶点数,\(M\)是边数。

二、判负环算法盘点

想到判负环,我们会想到很多的判负环算法。例如:

1. Bellman-Ford 判负环

这个算法在众多算法中最为经典,复杂度 \(O(N\times M)\)

2. SPFA 判负环

然而,这个算法是 Bellman-Ford 算法的队列优化版,这最短路方面卓有成效,但在判负环方面不见得有多少快。尽管在有负环的情况下会快很多,期望复杂度达到了 \(O(K\times M)\) (\(K\)是常数);但在没有负环的情况下,SPFA 算法会退化到 \(O(N\times M)\) 。

难道判负环的复杂度就由此停步于 \(O(N\times M)\) 之前吗?

不,还有办法的!

办法之一:SPFA之dfs版

3. SPFA_dfs 判负环

这个算法挺 科♂学 的,利用了 SPFA_dfs 可以迅速使大量节点得到更新,因此也更容易找到负环。然而,SPFA_dfs 死于不日前更新的毒瘤数据手里。

不要着急,我们还有办法!

4. 带卡界的 SPFA 算法

我们想到,在有负环的情况下,SPFA 判负环的时间复杂度是期望 \(O(M)\) 的,非常的快。那么反过来,效率低下是否就代表没有负环?

答案是肯定的!✔

假设入队操作超过了 \(T(N + M)\) 次,那么就认为没有负环。(\(T\) 一般取 \(2\))

$\large B!\space U!\space T!\space $

我们 WA 了!

所以放弃,回去用SPFA_bfs版 ✖

不!我们发现 11 个数据点只 WA 了 1 个点 (#9) ,还是比较不错的,所以我们想到增加 \(T\)。

我选择将数据下载了下来,在本地跑,经过二分,得出数据点#9的T最小是 \(K = 20.076030\space (eps=1^{-6})\) (少 \(0.000001\) 都不行)

然后就过了。

有点不太保险????

不过可以开大 \(T\) 啊!

下表给出了几组 \(T\) 的值对应的情况:

\(T\) 分值 时间消耗(ms) 对应评测记录id
2 91 58 R16135858
20.076030 100 198 R16135998
30 100 270 R16136029
100 100 754 R16136756
300 100 2071 R16136864

实际上耗时都不大。

实际上运用建议开 \(T = 2\) (一般没人卡这种算法【注:卡的方法点击箭头了解】如果你真的怕被卡,\(T\) 开大点也没事~~毕竟最多12个TLE~)

三、代码

#include <queue>
#include <cstdio>
#include <cstring>
using namespace std; inline int readint()
{
int flag = 1;
char c = getchar();
while ((c > '9' || c < '0') && c != '-')
c = getchar();
if (c == '-') flag = -1, c = getchar();
int init = c ^ '0';
while ((c = getchar()) <= '9' && c >= '0')
init = (init << 3) + (init << 1) + (c ^ '0');
return init * flag;
} struct Edge {
int v, w;
int nxt;
Edge() {}
Edge(int _v, int _w, int _nxt) : v(_v), w(_w), nxt(_nxt) {}
} edges[6007];
// 链式前向星存图
int top = 1;
int n, m; int head[2007] = {0};
int dis[2007] = {0};
bool inqueue[2007] = {0}; inline void add_edge(int u, int v, int w) // 单次加边操作
{
edges[top] = Edge(v, w, head[u]);
head[u] = top++;
} inline void add(int u, int v, int w) // 加边操作
{
add_edge(u, v, w);
if (w >= 0) add_edge(v, u, w);
} const double K = 20.076030; // 即题解中所说的 "T"
bool SPFA_bfs()
{
queue <int> q;
q.push(1);
inqueue[1] = 1;
int times = 0;
while (!q.empty()) {
times++;
if (times > K * (n + m)) return 1;
// 以上两行:卡界
int n = q.front(); q.pop();
inqueue[n] = 0;
for (int i = head[n]; i != -1; i = edges[i].nxt) {
Edge &e = edges[i];
if (dis[e.v] > dis[n] + e.w) {
dis[e.v] = dis[n] + e.w;
if (!inqueue[e.v]) q.push(e.v);
}
}
}
return 0;
} void van()
{
n = readint();
m = readint();
top = 1;
memset(head, -1, sizeof(head));
memset(dis, 0x3f, sizeof(dis));
memset(inqueue, 0, sizeof(inqueue));
dis[1] = 0;
register int ui, vi, wi;
for (register int i = 1; i <= m; i++) {
ui = readint();
vi = readint();
wi = readint();
add(ui, vi, wi);
}
if (SPFA_bfs()) puts("YE5");
else puts("N0");
} int main()
{
register int T = readint();
while (T--) van();
return 0;
}

洛谷 题解 P3385 【【模板】负环】的更多相关文章

  1. 洛谷P3385 [模板]负环 [SPFA]

    题目传送门 题目描述 暴力枚举/SPFA/Bellman-ford/奇怪的贪心/超神搜索 输入输出格式 输入格式: 第一行一个正整数T表示数据组数,对于每组数据: 第一行两个正整数N M,表示图有N个 ...

  2. 题解-洛谷P5410 【模板】扩展 KMP(Z 函数)

    题面 洛谷P5410 [模板]扩展 KMP(Z 函数) 给定两个字符串 \(a,b\),要求出两个数组:\(b\) 的 \(z\) 函数数组 \(z\).\(b\) 与 \(a\) 的每一个后缀的 L ...

  3. 题解-洛谷P4724 【模板】三维凸包

    洛谷P4724 [模板]三维凸包 给出空间中 \(n\) 个点 \(p_i\),求凸包表面积. 数据范围:\(1\le n\le 2000\). 这篇题解因为是世界上最逊的人写的,所以也会有求凸包体积 ...

  4. 洛谷P1919 【模板】A*B Problem升级版 题解(FFT的第一次实战)

    洛谷P1919 [模板]A*B Problem升级版(FFT快速傅里叶) 刚学了FFT,我们来刷一道模板题. 题目描述 给定两个长度为 n 的两个十进制数,求它们的乘积. n<=100000 如 ...

  5. 洛谷P3387 【模板】缩点 题解

    背景 今天\(loj\)挂了,于是就有了闲情雅致来刷\(luogu\) 题面 洛谷P3387 [模板]缩点传送门 题意 给定一个\(n\)个点\(m\)条边有向图,每个点有一个权值,求一条路径,使路径 ...

  6. 洛谷p3384【模板】树链剖分题解

    洛谷p3384 [模板]树链剖分错误记录 首先感谢\(lfd\)在课上调了出来\(Orz\) \(1\).以后少写全局变量 \(2\).线段树递归的时候最好把左右区间一起传 \(3\).写\(dfs\ ...

  7. 洛谷P3377 【模板】左偏树(可并堆) 题解

    作者:zifeiy 标签:左偏树 这篇随笔需要你在之前掌握 堆 和 二叉树 的相关知识点. 堆支持在 \(O(\log n)\) 的时间内进行插入元素.查询最值和删除最值的操作.在这里,如果最值是最小 ...

  8. 洛谷 P3384 【模板】树链剖分-树链剖分(点权)(路径节点更新、路径求和、子树节点更新、子树求和)模板-备注结合一下以前写的题目,懒得写很详细的注释

    P3384 [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节 ...

  9. 洛谷 P3387 【模板】缩点 DAGdp学习记

    我们以洛谷P3387 [模板]缩点 来学习DAGdp 1.这道题的流程 //伪代码 for i->n if(i未被遍历) tarjan(i) 缩点() DAGdp() 完成 首先tarjan这部 ...

随机推荐

  1. maven打包记录1

    在需要打包的项目目录下找到pom.xml文件 (过程中可能遇到 :-Dmaven.multiModuleProjectDirectory system property is not set. Che ...

  2. iOS地理反地理编码--CoreLocation

    .sidebar{float:left;width:220px;} .container-fluid>.content{margin-left:240px;} a{color:#0069d6;t ...

  3. [java] 笔记 from黑马

    1. 关于String的创建.   PS:String的底层是用字节数组来实现的. 2.字符串常量池的笔记 具体指向是如下图的, 注意看0x666和0x999这两个地址. 3.原因如下: 4. 5. ...

  4. pat 1006 Sign In and Sign Out(25 分)

    1006 Sign In and Sign Out(25 分) At the beginning of every day, the first person who signs in the com ...

  5. mysql 索引笔记

    MyISAM引擎的B+Tree的索引 通过上图可以直接的看出, 在MyISAM对B+树的运用中明显的特点如下: 所有的非叶子节点中存储的全部是索引信息 在叶子节点中存储的 value值其实是 数据库中 ...

  6. 力扣(LeetCode)颠倒二进制位 个人题解

    颠倒给定的 32 位无符号整数的二进制位. 示例 1: 输入: 00000010100101000001111010011100 输出: 0011100101111000001010010100000 ...

  7. 用安全密钥验证ssh

    1.需要打开两台虚拟机,并保证两台虚拟机可以ping通: 本地主机IP:192.168.8.120 远程主机IP:192.168.8.100 2.在本地主机生成密钥对,输入命令“ssh-keygen” ...

  8. libwebsocket协议切换状态机

    libwebsocket为连接(connection)定义了一组状态机-lws_connection_states,通过状态机我们来看libwebsocket如何实现协议的切换.除了lws_conne ...

  9. PL真有意思(二):程序设计语言语法

    前言 虽然标题是程序语言的语法,但是讲的是对词法和语法的解析,其实关于这个前面那个写编译器系列的描述会更清楚,有关语言语法的部分应该是穿插在整个设计当中的,也看语言设计者的心情了 和英语汉语这些自然语 ...

  10. MyEclipse使用总结

    0.快捷键 ================================================================================ 编辑: Ctrl+Shif ...