图上负环判定小记

本文全文参考了 《算法竞赛进阶指南》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 的时候说明有负环。(我还不懂这个)

posted @ 2020-11-29 15:15  xwmwr  阅读(349)  评论(0编辑  收藏  举报