https://vjudge.net/contest/66569#problem/F
题意:判断图中是否存在负权回路
首先,介绍图的邻接表存储方式
邻接表建图,类似于头插法建单链表
head[x]:以x为源点的第一条边,初始值为-1.
struct edge
{
int to;
int weight;
int next;
}e[maxn];
to表示被指向的点;weight表示这条边的权重;next表示源点同为x的下一条边,这是遍历以x为源点的的关键
SPFA算法中的队列与BFS不同的是,每个点都可以在重复进入队列,而且进入队列总次数大于顶点总数说明该图存在负环。这是因为每个点的估计最短路可能在出队列后被更新,这样这个点就可以再次进入队列去更新其他点。
1 #include<iostream> 2 #include<cstdio> 3 #include<string> 4 #include<cstring> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 using namespace std; 9 const int maxn=5205; 10 const int inf=0x3f3f3f3f; 11 int n,m,w; 12 struct edge 13 { 14 int to; 15 int time; 16 int next; 17 }e[maxn]; 18 int head[505]; 19 20 int Spfa(int src) 21 { 22 //记录每个顶点到src的距离,除了src,其余点都初始化为无穷大 23 int dis[505]; 24 memset(dis,inf,sizeof(dis)); 25 dis[src]=0; 26 //记录每个顶点进入队列的总次数,大于n说明有负环 27 int cnt[505]; 28 memset(cnt,0,sizeof(cnt)); 29 //记录是否在队列中 30 bool inque[505]; 31 memset(inque,0,sizeof(inque)); 32 queue<int> Q; 33 //源点进如队列 34 Q.push(src); 35 inque[src]=1; 36 cnt[src]++; 37 while(!Q.empty()) 38 { 39 int q=Q.front(); 40 Q.pop(); 41 //记录已经出队列 42 inque[q]=0; 43 //邻接表,i表示边 44 for(int i=head[q];i!=-1;i=e[i].next) 45 { 46 //对每个点进行松弛,逐渐逼近最小值 47 if(dis[q]+e[i].time<dis[e[i].to]) 48 { 49 dis[e[i].to]=dis[q]+e[i].time; 50 //如果更新成功而且当前不在队列中,进入队列且总次数加1 51 if(!inque[e[i].to]) 52 { 53 inque[e[i].to]=1; 54 cnt[e[i].to]++; 55 Q.push(e[i].to); 56 //说明存在负环 57 if(cnt[e[i].to]>n) 58 { 59 return 1; 60 } 61 } 62 } 63 } 64 } 65 return 0; 66 } 67 int main() 68 { 69 int T; 70 scanf("%d",&T); 71 int x,y,t; 72 while(T--) 73 { 74 memset(head,-1,sizeof(head)); 75 scanf("%d%d%d",&n,&m,&w); 76 int tot=0; 77 for(int i=1;i<=m;i++) 78 { 79 scanf("%d%d%d",&x,&y,&t); 80 e[tot].to=y; 81 e[tot].time=t; 82 e[tot].next=head[x]; 83 head[x]=tot++; 84 e[tot].to=x; 85 e[tot].time=t; 86 e[tot].next=head[y]; 87 head[y]=tot++; 88 } 89 for(int i=1;i<=w;i++) 90 { 91 scanf("%d%d%d",&x,&y,&t); 92 e[tot].to=y; 93 e[tot].time=-t; 94 e[tot].next=head[x]; 95 head[x]=tot++; 96 } 97 int ans=Spfa(1); 98 if(ans==1) 99 { 100 puts("YES"); 101 } 102 else 103 { 104 puts("NO"); 105 } 106 } 107 return 0; 108 }
理论上以任意一点为源点都是可以的,顶点的数据范围是1~N,所以Spfa(1)或Spfa(n)都可以AC,其他的具体值不可以