SPFA 判负环
SPFA 判负环
大家好,我是Weekoder!
今天我要讲的是接上一次 SPFA 最短路算法衍生而来的一个应用——判断图中是否存在负环。我将介绍两种判负环的方法,都基于 SPFA。
负环的概念
负环是什么?
负环就是在图中的一个环,其边权之和为负数。如下图:
可以看到,这个环的权值和是
如果一个图有负环,则该图没有最短路,因为可以在负环中无限绕圈,不断减少路径长度,一直到
BFS-SPFA 判负环
今天介绍的第一种方法是基于 BFS 的搜索方式的判定方法。在 SPFA 模板的基础上,只修改了一点点,非常容易。它的原理是:维护一个
参考题目:P3385。
\text{Code:}
bool spfa(int s) {
queue<int> q;
memset(dis, 0x3f, sizeof dis);
memset(vis, 0, sizeof vis);
memset(dp, 0, sizeof dp); // 记得初始化
dis[s] = 0;
vis[s] = 1;
q.push(s);
while (!q.empty()) {
int cur = q.front(); q.pop();
vis[cur] = 0;
for (auto nxt : nbr[cur]) {
int to = nxt.to, w = nxt.w;
if (dis[to] > dis[cur] + w) {
dis[to] = dis[cur] + w;
dp[to] = dp[cur] + 1; // 状态转移方程
if (dp[to] >= n) return 1; // 如果存在负环,则返回1
if (!vis[to]) {
vis[to] = 1;
q.push(to);
}
}
}
}
return 0;
}
DFS-SPFA 判负环
这个方法是我在做 P3199 最小圈的时候,因为不知道为什么
\text{Code:}
bool spfa(int cur) {
vis[cur] = 1;
for (auto nxt : nbr[cur]) {
int to = nxt.to, w = nxt.w;
if (dis[to] > dis[cur] + w) {
dis[to] = dis[cur] + w;
if (vis[to] || spfa(to)) return 1;
}
}
vis[cur] = 0;
return 0;
}
可以看到,
BFS-SPFA 对比 DFS-SPFA
如果你去实践了一下,你会发现:诶?DFS 的版本过不了模板,BFS 却能过。DFS 是不是比 BFS 慢?不,听我来分析一下他们的区别。DFS-SPFA 其实比 BFS-SPFA 要快得多。你会发现评测记录中其他测试点基本上都是几毫秒,都没有超过
然而事实上还是推荐大家用 BFS-SPFA,因为 DFS-SPFA 太容易被卡了。
小结
综上所述,SPFA 判负环的方法就是这些了。请不要忘记关注下一次的文章:负环的习题和应用。