来自题解:https://www.luogu.org/wiki/show?name=题解+P3385
1.Bellman-Ford
通过Belman-Ford求出最短路,然后在进行一遍松弛操作,如果可以再松弛说明存在负环,否则不存在。
2.SPFA
SPFA有两种实现方法。一个是BFS一个是DFS。
1.BFS
BFS版的判断标准:是否存在某个节点入队超过n次
BFS_SPFA的期望时间复杂度是O(ke),其中k为所有顶点进队的平均次数。
如果存在负环嘛,这个期望的时间复杂度就真的是期望了。
2.DFS
DFS版判断标准:否存在一点在一条路径上出现多次来判断。
时间复杂度如果没记错是O(nlogn)的。
3.DFS优化
既然我们只需要判断负环,那么就相当于我们需要找到一条权值和为负的回路。
既然我们只需要找到权值和为负的回路,那不妨使距离数组d初始化为0。
这样处理后,第一次拓展只会拓展到与起点相连边权为负的边。
那么我们就分别枚举所有的点作为起点,如果已经找到一个负环就不再继续枚举。
根据SPFA,我们找到的负环一定包含当前枚举的这个点。(因为这个点出现了两次啊)
——代码

1 #include <cstdio> 2 #include <cstring> 3 4 using namespace std; 5 6 const int MAXN = 400001; 7 int T, n, m, cnt; 8 int head[MAXN], to[MAXN], next[MAXN], val[MAXN], dis[MAXN]; 9 bool vis[MAXN], flag; 10 11 inline void add(int x, int y, int z) 12 { 13 to[cnt] = y; 14 val[cnt] = z; 15 next[cnt] = head[x]; 16 head[x] = cnt++; 17 } 18 19 inline void spfa(int u) 20 { 21 int i, v; 22 vis[u] = 1; 23 for(i = head[u]; i != -1; i = next[i]) 24 { 25 v = to[i]; 26 if(dis[u] + val[i] < dis[v]) 27 { 28 dis[v] = dis[u] + val[i]; 29 if(vis[v]) 30 { 31 flag = 1; 32 return; 33 } 34 else spfa(v); 35 } 36 } 37 vis[u] = 0; 38 } 39 40 int main() 41 { 42 int i, x, y, z; 43 scanf("%d", &T); 44 while(T--) 45 { 46 scanf("%d %d", &n, &m); 47 cnt = flag = 0; 48 memset(vis, 0, sizeof(vis)); 49 memset(dis, 0, sizeof(dis)); 50 memset(head, -1, sizeof(head)); 51 for(i = 1; i <= m; i++) 52 { 53 scanf("%d %d %d", &x, &y, &z); 54 add(x, y, z); 55 if(z >= 0) add(y, x, z); 56 } 57 for(i = 1; i <= n && !flag; i++) spfa(i); 58 if(flag) printf("YE5 "); 59 else printf("N0 "); 60 } 61 return 0; 62 }