【洛谷P3385】模板-负环

这道题普通的bfs spfa或者ballen ford会T

所以我们使用dfs spfa

原因在于,bfs sfpa中每个节点的入队次数不定,退出操作不及时,而dfs则不会

既然,我们需要找负环,那么我们不妨将dis数组初始化为0,以每个点为起点进行dfs spfa

这样第一次扩展到的只有边权为负的边,之后若再次走到以访问过的点一定是负权回路

记得每次更换起点时清零vis数组

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=200010,M=400010;
 6 int n,m,size,sg,vis[N],d[N];
 7 int head[M],to[M],nxt[M],val[M];
 8 void uni(int x,int y,int z){
 9     size++;
10     nxt[size]=head[x];
11     head[x]=size;
12     to[size]=y;
13     val[size]=z;
14 }
15 void dfs_spfa(int x){
16     if (sg) return;
17     vis[x]=1;
18     for (int k=head[x];k;k=nxt[k]){
19         if (sg) return;
20         int y=to[k];
21         if (d[x]+val[k]<d[y]){
22             d[y]=d[x]+val[k];
23             if (vis[y]){
24                 sg=1;
25                 return;
26             }
27             else
28                 dfs_spfa(y);
29         }
30     }
31     vis[x]=0;
32 }
33 int main(){
34     int a,b,w,T;
35     scanf("%d",&T);
36     while (T--){
37         size=sg=0;
38         scanf("%d %d",&n,&m);
39         memset(d,0,sizeof(d));
40         memset(head,0,sizeof(head));
41         memset(vis,0,sizeof(vis));
42         for (int i=1;i<=m;i++){
43             scanf("%d %d %d",&a,&b,&w);
44             uni(a,b,w);
45             if (w>=0) uni(b,a,w);
46         }
47         for (int i=1;i<=n;i++){
48             dfs_spfa(i);
49             if (sg) break;
50         }
51         if (sg) printf("YE5\n");
52         else printf("N0\n");
53     }
54     return 0;
55 }

时间: 2024-10-12 16:18:44

【洛谷P3385】模板-负环的相关文章

洛谷P3385 【模板】负环 DFS-SPFA 判负环 图论

洛谷P3385 [模板]负环 图论 今天get了 一个 DFS-SPFA 判负环的方法 一般的 BFS-SPFA 判负环 一般就是 不停地做,如果某点第 n+1次加入队列中,那么说明这个图存在负环然而我并不会证明,期望复杂度是 O(kM) k 大约是在 2 左右 但是其实对于一些极限数据,最坏可以把他卡到 O( NM) 额,这就直接炸飞了是不是,而且据说,一些数据比较强的题目,总会想到卡一卡SPFA的, 然后我们换一种思路 因为题目中一定存在一种 负环对吧,所以说假如你某段路径权值和为自然数的时

洛谷—— P3385 【模板】负环

题目描述 暴力枚举/SPFA/Bellman-ford/奇怪的贪心/超神搜索 输入输出格式 输入格式: 第一行一个正整数T表示数据组数,对于每组数据: 第一行两个正整数N M,表示图有N个顶点,M条边 接下来M行,每行三个整数a b w,表示a->b有一条权值为w的边(若w<0则为单向,否则双向) 输出格式: 共T行.对于每组数据,存在负环则输出一行"YE5"(不含引号),否则输出一行"N0"(不含引号). 输入输出样例 输入样例#1: 2 3 4 1

【C++】最近公共祖先LCA(Tarjan离线算法)&amp;&amp; 洛谷P3379LCA模板

1.前言 首先我们介绍的算法是LCA问题中的离线算法-Tarjan算法,该算法采用DFS+并查集,再看此算法之前首先你得知道并查集(尽管我相信你如果知道这个的话肯定是知道并查集的),Tarjan算法的优点在于相对稳定,时间复杂度也比较居中,也很容易理解(个人认为). 2.思想 下面详细介绍一下Tarjan算法的思想: 1.任选一个点为根节点,从根节点开始. 2.遍历该点u所有子节点v,并标记这些子节点v已被访问过. 3.若是v还有子节点,返回2,否则下一步. 4.合并v到u上. 5.寻找与当前点

AC自动机(附洛谷P3769模板题)

首先,介绍一下AC自动机(Aho-Corasick automaton),是一种在一个文本串中寻找每一个已给出的模式串的高效算法. 在学习AC自动机之前,你需要先学习Trie树和KMP算法,因为AC自动机正式利用并结合了两者的思想. 说到实际的不同,其实AC自动机只是在Trie树上引入了一个类似KMP中next数组的东西叫做Fail指针. 对于每一个节点,Fail指针指向该节点所代表的字符串中,次长的.在Trie树中存在的后缀(因为最长的在Trie树种存在的后缀就是其本身)所代表的节点. 举例:

洛谷P3375 [模板]KMP字符串匹配

To 洛谷.3375 KMP字符串匹配 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习一下就知道了. 输入输出格式 输入格式: 第一行为一个字符串,即为s1(仅包含大写字母) 第二行为一个字符串,即为s2(仅包含大写字母) 输出格式: 若干行,每行包含一个整数,表示s2在s1中出现的位置 接下来1行,包括length(s2)个整

洛谷.3803.[模板]多项式乘法(FFT)

题目链接:洛谷.LOJ. FFT相关:快速傅里叶变换(FFT)详解.FFT总结.从多项式乘法到快速傅里叶变换. #include <cmath> #include <cctype> #include <cstdio> #include <algorithm> #define gc() getchar() const int N=1e6+5; const double PI=acos(-1); int n,m; struct Complex { double

洛谷.1919.[模板]A乘B Problem升级版(FFT)

题目链接:洛谷.BZOJ2179 //将乘数拆成 a0*10^n + a1*10^(n-1) + ... + a_n-1的形式 //可以发现多项式乘法就模拟了竖式乘法 所以用FFT即可 注意处理进位 //n位*n位最多就只有2n位了 //论putchar的速度..还是快的 #include <cmath> #include <cstdio> #include <cctype> #include <algorithm> #define gc() getchar

[模板]负环

在博大精深的图论算法中有这样一个神奇的存在! 当我们求最短路时,往往会发现有边权为负的情况存在,这时候我们的dijksra便不能很好的胜任他的职务了. 那么伟大的spfa算法就出现了(至于同学们在刚接触这个算法的时候,一定会听到:关于SPFA,他死了,这是因为dfs优化下的spfa时间复杂度极优,亲测是dijksta的10分之1左右,但是它有着明显的缺陷, 容易被出题人的极端数据卡掉,所以我们今天讲的是常用的bfs的spfa) 我们用一个队列储存所有的点,用vis数组储存他是访问过了,剩下的就是

洛谷 [P2483] [模板] k短路

人生中的第一道黑题... 其实就是k短路模板 #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <cstdlib> #include <queue> using namespace std; const int MAXN=400005; int init(){ int