给定一个n个点m条边的有向图,图中可能存在重边和自环, 边权可能为负数。
请你判断图中是否存在负权回路。
第一行包含整数n和m。
接下来m行每行包含三个整数x,y,z,表示存在一条从点x到点y的有向边,边长为z。
如果图中存在负权回路,则输出“Yes”,否则输出“No”。
1≤n≤20001≤n≤2000,
1≤m≤100001≤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 }
原文:https://www.cnblogs.com/sxq-study/p/12236710.html