一直觉得紫书代码比较精炼,就照着紫书上不完整的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 }