方法一: 在
SPFA
\text{SPFA}
SPFA 的过程中顺便记一个变量
c
n
t
[
x
]
cnt[x]
cnt[x] ,表示
1
→
x
1\to x
1→x 的最短路上经过的边数,在松弛时顺带判断,若存在一个点
x
x
x 满足
c
n
t
[
x
]
≥
n
cnt[x]\ge n
cnt[x]≥n,则图中存在负环。
方法二: 在
SPFA
\text{SPFA}
SPFA 的过程中顺便记下每个点的入队次数,在松弛时顺带判断,若某时刻存在一个点的入队次数达到
n
n
n,则图中存在负环。
两种方法的时间复杂度均为
O
(
n
m
)
\mathcal O(nm)
O(nm),其他诸如
dfsSPFA
\text{dfsSPFA}
dfsSPFA 的奇怪的玄学算法的时间复杂度可能是指数级的,非常不科学,可以被负责任的出题人卡掉。
附方法一代码:
constint MaxNV =2e3+5;constint MaxNE =6e3+5;constint INF =0x3f3f3f3f;#define trav(u) for (int e = adj[u], v; v = to[e], e; e = nxt[e])int n, m;int dis[MaxNV], cnt[MaxNV];int ect, adj[MaxNV], to[MaxNE], nxt[MaxNE], len[MaxNE];inlinevoidaddEdge(int u,int v,int w){
nxt[++ect]= adj[u];
adj[u]= ect;
to[ect]= v;
len[ect]= w;}inlineboolSPFA(){staticbool inq[MaxNV];staticint que[MaxNV * MaxNE], qr;
que[qr =1]=1;for(int i =1; i <= n;++i)
inq[i]=false;for(int ql =1, u; ql <= qr;++ql){
inq[u = que[ql]]=false;trav(u)if(tense(dis[v], dis[u]+ len[e])){
cnt[v]= cnt[u]+1;if(cnt[v]>= n)returntrue;if(!inq[v])
inq[que[++qr]= v]=true;}}returnfalse;}