一直觉得紫书代码比较精炼,就照着紫书上不完整的SPFA算法写了一道判断是否有负权边的题,题目链接:https://vjudge.net/problem/POJ-3259,细节看代码
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <cmath> 5 #include<iostream> 6 #include<vector> 7 #include<set> 8 #include<queue> 9 #define MAXN 500100 10 #define INF 0x3f3f3f3f 11 using namespace std; 12 typedef long long ll; 13 int n,m,w; 14 struct node 15 { 16 int from,to,cost; 17 node(int a,int b,int c):from(a),to(b),cost(c){} 18 };///边的结构体 19 vector<int>G[MAXN];///G[i]中的元素代表以i为起点的边 20 vector<node>edges;///存放所有的边 21 bool inq[MAXN]; 22 int d[MAXN],cnt[MAXN]; 23 bool SPFA(int s) 24 { 25 26 for(int i=0;i<=n;i++)d[i]=INF; 27 memset(inq,0,sizeof(inq)); 28 memset(cnt,0,sizeof(cnt));///初始化 29 d[s]=0; 30 inq[s]=true; 31 queue<int> q; 32 q.push(s); 33 while(!q.empty()) 34 { 35 int u=q.front();q.pop(); 36 inq[u]=false; 37 for(int i=0;i<G[u].size();i++)///对以队首为起点的边进行松弛 38 { 39 node& e=edges[G[u][i]]; 40 if(d[u]<INF&&d[e.to]>d[u]+e.cost) 41 { 42 d[e.to]=d[u]+e.cost; 43 if(!inq[e.to])///每松弛一个点加入队列 44 { 45 q.push(e.to); 46 inq[e.to]=true; 47 if(++cnt[e.to]>n)return false;///如果一个点被松弛n次以上说明有负环 48 } 49 } 50 } 51 } 52 return true; 53 } 54 void AddEdge(int from,int to,int dist) 55 { 56 edges.push_back(node(from,to,dist)); 57 int k = edges.size(); 58 G[from].push_back(k-1);///初始化边,将他们编号 59 } 60 int main() 61 { 62 int t; 63 scanf("%d",&t); 64 while(t--) 65 { 66 scanf("%d%d%d",&n,&m,&w); 67 for(int i=1;i<MAXN;i++)G[i].clear(); 68 edges.clear(); 69 for(int i=0;i<m;i++) 70 { 71 int u,v,cost; 72 scanf("%d%d%d",&u,&v,&cost); 73 AddEdge(u,v,cost);AddEdge(v,u,cost);///这里路径是双向的(我这里被卡很久) 74 } 75 for(int i=0;i<w;i++) 76 { 77 int u,v,cost; 78 scanf("%d%d%d",&u,&v,&cost); 79 AddEdge(u,v,-cost);///虫洞权值为负,且为单向 80 } 81 if(!SPFA(1))printf("YES\n"); 82 else printf("NO\n"); 83 } 84 return 0; 85 }