本文全文参考了 《算法竞赛进阶指南》by lydrainbowcat
如果一个环上所有边的权值和为负数,称其为负环。
常用的能够判断负环的算法一般就是 Bellman-Ford 系的最短路算法。
若图中存在负环,那么直观表现为:总是存在一条边 ((x,y)), 使得 (sf d[y]le d[x]+w(x,y)) 不被满足。根据抽屉原理, 若源点到节点 (x) 的最短路包含 (ge n) 条边, 那么这条路径必然重复经过了某个点 (p), 如果这个环是正环, 显然去掉这个环后会得到一条更短的最短路, 与假设矛盾, 于是这个环必定是负环, 由负环的性质知从源点到节点 x 不存在最短路。
Bellman-Ford 算法判定负环
若经过 n 次迭代后, 算法未结束, 则图中存在负环, 反之不存在。
示例代码, 参考了 OI-wiki:
bool Bellman_Ford() {
for(int i=0; i<n; ++i) {
bool jud = false;
for(int j=1; j<=n; ++j)
for(int k=h[j]; ~k; k=nxt[k])
if(dist[p[k]] > dist[j] + w[k])
dist[p[k]] = dist[p[k]] + w[k],
jud = true;
if(!jud) break;
}
for(int j=1; j<=n; ++j)
for(int k=h[j]; ~k; k=nxt[k])
if(dist[p[k]] > dist[j] + w[k])
return true;
return false;
}
队列优化的 Bellman-Ford 判负环:
设 (cnt[x]) 表示从源点到 (x) 的最短路经过的边数, 在最短路执行的过程中维护其, 不难发现可以轻松地判断某一时刻是否有某个 (x) 满足 (cnt[x]ge n), 就可以判负环了。
另一种方法是记录每个点入队的次数,次数达到 n 的时候说明有负环。(我还不懂这个)