圖上負環判定小記

本文全文參考了 《算法競賽進階指南》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 的時候說明有負環。(我還不懂這個)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章