BellmanFord的优化:SPFA算法

关于SPFA

  • 它死了

致敬NOI凉心出题人以及……

单源最短路奇技淫巧之SPFA算法😎😎😎

用途

  • 可以用SPFA求有负边权图的最短路
  • 求出图中是否存在负环

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include<iostream>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
inline int read(){int x=0,f=1;char c=getchar();for(;!isdigit(c);c=getchar())if(c=='-')f=-1;for(;isdigit(c);c=getchar())x=(x<<3)+(x<<1)+(c^48);return x*f;}
int n,m,s;
struct node{
int to;
int val;
};
vector<node>ro[100005];
int dis[100005],cnt[100005];
bool vis[100005];
queue<int>Q;
bool spfa(){
memset(dis,0x3f3f3f3f,sizeof dis);
dis[s]=0,vis[s]=true/* 这里的vis[]表示的是当前点是否在队列中 */;Q.push(s);
while(Q.size()){
int now = Q.front();Q.pop();
vis[now]=false;
for(node to:ro[now]){
if(dis[to.to]>dis[now]+to.val){
dis[to.to]=dis[now]+to.val;//进行一次松弛操作
cnt[to.to]=cnt[now]+1;//松弛次数+1
if(cnt[to.to]>=n)return false;
/*
每一轮松弛最少使一条边松至最短,那么最多松弛n-1次就能找到最短路
如果松弛了超过n-1次,则说明存在负环
*/
if(!vis[to.to])Q.push(to.to),vis[to.to]=true;
}
}
}
return true;
}
int main(){
n=read(),m=read(),s=read();
for(int i = 1,u,v,w;i<=m;i++){
u=read(),v=read(),w=read();
ro[u].push_back((node){v,w});
}
bool NO_NEGTIVE_CIRCLE = spfa();//判断有无负环
if(NO_NEGTIVE_CIRCLE){
for(int i = 1;i<=n;i++){
cout<<dis[i]<<" ";
}
}else cout<<-1;
return 0;
}

后话

使用SPFA,我们可以完成差分约束