淺談SPFA判負環


SPFA判負環

有不足的地方請指出
本蒟蒻一定會修改吼

【前言】

最短路的求法中最廣為人知的我僅僅知道的,有弗洛伊德,dijkstra和SPFA。
弗洛伊德最簡單的三重循環,復雜度n^3,一般也就做個n小的題目,遇到n大一點的(超過1000)幾乎就只能拿部分分。
SPFA是一種廣為人知的已經死掉的算法(某人說過一道圖論題如果不卡卡SPFA就不是一道好的圖論題目),但是他卻有一個很重要的作用,是其他三者無法代替的,那就是這篇博客的題目,判負環!
dijkstra是這三種里面最為穩定的一種算法,何為穩定,弗洛伊德只能跑那么小的數據范圍就可以看出來,在很多題目上面只能打一下暴力,SPFA就更不用多說了他死了,所以dijkstra理所當然的成為了最穩定的算法。

說這么多就是為了引出SPFA判負環!

【不可代替性】

dijkstra和弗洛伊德都是判斷不了負環的
弗洛伊德可以判斷負環
但是我不會
我也不想會
人家SPFA好不容易有一個活着的理由干嘛要給人家扼殺掉
dijkstra遇到負權邊就死了
更別說負環了
但是SPFA可以判斷負環
具體原因不多贅述了,學過dijkstra和弗洛伊德的應該都知道
但是我不知道

【具體實現】

SPFA的過程

每次都拿一個點到起點的距離來松弛其他的點到起點的距離

判負環

負環是一個邊權值和等於負數的環
可以想想一下
如果SPFA遇到了負環會出現什么情況
一直松弛下去
因為每次出現的負數都可以讓目前最短的邊變得更短
所以可以根據這一點
開一個數組用來記錄這是這一條鏈上第幾個入隊的數
然后每次松弛的時候都把到達的點入隊的數標為前面這個點入隊的次數+1,因為這是一個順序的過程
就像是1,2,3……這樣的數列
然后如果出現了負環就會和上面說的一樣一直松弛下去
然后這個負環上的點入隊的數就會不斷變大
可以想一下
如果n個數連成一個點
那入隊數最大才只能是n
所以只要某個點的入隊數大於了n
那就可以證明他在不停得松弛
也就是出現了負環

【核心代碼】

bool SPFA(int acioi)
{
	queue<int>q;
	for(register int i = 1;i <= n;++ i)
		d[i] = 99999999;
	d[acioi] = 0;
	q.push(acioi);
	while(!q.empty())
	{
		int x = q.front();
		q.pop();use[x] = false;
		for(register int i = head[x];i != 0;i = a[i].ne)
		{
			int y = a[i].y;
			if(d[y] > d[x] + a[i].z)
			{
				d[y] = d[x] + a[i].z;
				cnt[y] = cnt[x] + 1;
				if(cnt[y] > n)
					return false;
				if(use[y] == false)
				{
					use[y] = true;
					q.push(y);
				}
			}
		}
	}
	return true;
}

【例題】

洛谷P2136 拉近距離
SPFA判負環板子題
詳情解釋請看
這里

洛谷P3385 【模板】負環
同樣也是板子題
想請解釋請看
這里


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM