一、声明

在下面的描述中,未说明的情况下,\(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. Docker学习-Docker搭建Consul集群

    1.环境准备 Linux机器三台 网络互通配置可以参考 https://www.cnblogs.com/woxpp/p/11858257.html 192.168.50.21 192.168.50.2 ...

  2. nyoj 72-Financial Management (求和 ÷ 12.0)

    72-Financial Management 内存限制:64MB 时间限制:3000ms 特判: No 通过数:7 提交数:12 难度:1 题目描述: Larry graduated this ye ...

  3. 浅谈Node中的模块化

    关于这篇文章早在去年年初的时候我就想写一片关于模块化的文章,但是推到现在才来完成也有很多好处,巩固之前对Node的理解.毕竟在我目前的项目中还没有一款项目是用到了Node开发,所以导致我对Node的一 ...

  4. python接口自动化--Excel

    1.操作步骤: (1)安装python官方Excel库-->xlrd (2)获取Excel文件位置并读取 (3)读取sheet (4)读取指定rows和cols内容 2.示例代码 # -*- c ...

  5. 看淡生死,不服就干(C语言指针)

    看淡生死,不服就干 emmmmm 其实今天蛮烦的 高等数学考的一塌糊涂 会的不会的都没写 真心没有高中轻松了啊 也不知道自己立的flag还能不能实现 既然选择了就一定坚持下去啊 下面还是放一段之前写的 ...

  6. PHP提高SESSION响应速度的方法有哪些

    1.设置多级目录存储SESSION 默认session的存储目录是1级目录,如果用户量比较大,session文件数量就比较大,我们可以设置目录数为2,使用2级目录可以提交查找和存取速度.不过这种方式对 ...

  7. Matlab查看本机IP地址---xdd

    复制粘贴于http://www.matlabsky.com/thread-28597-1-1.html [s, r]=system('ipconfig') % r=regexp(r,'IP Addre ...

  8. All-in-one 的Serving分析

    export_func.export(model, sess, signature_name=mission, version=fold + 1) def export(model, sess, si ...

  9. AI如何驱动软件开发?华为云DevCloud 权威专家邀你探讨

    近期,国际著名咨询公司Gartner 在一份研究报告中将 "AI-Driven Development" 列为 2019 年的 Top 10 Strategic Technolog ...

  10. Reactive(1) 从响应式编程到"好莱坞"

    目录 概念 面向流设计 异步化 响应式宣言 参考文档 概念 Reactive Programming(响应式编程)已经不是一个新东西了. 关于 Reactive 其实是一个泛化的概念,由于很抽象,一些 ...