使用spfa算法判断有没有负环

如果存在最短路径的边数大于等于点数,就有负环

给定一个n个点m条边的有向图,图中可能存在重边和自环, 边权可能为负数。

请你判断图中是否存在负权回路。

输入格式

第一行包含整数n和m。

接下来m行每行包含三个整数x,y,z,表示存在一条从点x到点y的有向边,边长为z。

输出格式

如果图中存在负权回路,则输出“Yes”,否则输出“No”。

数据范围

1n20001≤n≤2000,
1m100001≤m≤10000,
图中涉及边长绝对值均不超过10000。

输入样例:

3 3
1 2 -1
2 3 4
3 1 -4

输出样例:

Yes


###########################################

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 //优化的贝尔曼福特算法,就是spfa算法,用更新过的点去更新和它相连接的点
 4 const int N = 2010, M = 10010;
 5 int h[N], e[M], w[M], ne[M];
 6 int idx;
 7 int dist[N], cnt[N];
 8 bool flag[N];//代表该节点当前是否在队列里
 9 int n, m;
10 
11 void add(int a, int b, int c){
12     w[idx] = c; e[idx] = b;       
13     ne[idx] = h[a];
14     h[a] = idx ++;
15 }
16 
17 bool spfa(){
18     queue<int> q;//队列中存储的是已经更新过用来更新其他节点的点
19     //所有的点都是起点,加入队列
20     for(int i = 1;i <= n;++i){
21         q.push(i);
22         flag[i] = true;
23     }
24     while(!q.empty()){
25         int t = q.front(); q.pop();
26         flag[t] = false;//移除队列里
27         for(int i = h[t];i != -1;i = ne[i]){
28             int j = e[i];
29             //更新成功
30             if(dist[j] > dist[t] + w[i]){
31                 dist[j] = dist[t] + w[i];
32                 cnt[j] = cnt[t] + 1;//更新边数
33                 if(cnt[j] >= n)return true;
34                 if(!flag[j]) {//如果j不在队列里
35                     q.push(j);
36                     flag[j] = true;//放进队列里
37                 }
38             }
39         }
40     }
41     return false;
42 }
43 
44 int main(){
45     scanf("%d%d", &n, &m);
46     memset(h, -1, sizeof h);
47     while(m--){
48         int x, y, z;
49         scanf("%d%d%d", &x, &y, &z);
50         add(x, y, z);
51     }
52     if (spfa()) puts("Yes");
53     else puts("No");
54 }
View Code
原文地址:https://www.cnblogs.com/sxq-study/p/12236710.html