Bellman Ford演算法及其佇列優化與實戰入門

2021-07-22 08:01:49 字數 2544 閱讀 3357

bellman-ford演算法能解決負權邊的圖,就是說能夠來判斷存在負環。

先來看一下核心**:

dis[i]      為源點到i點的最短路 

for(k = 1; k <= n-1; k++) //n為頂點的個數

for(int i = 1; i <= m; i++) //m為邊的條數

if(dis[v[i]] > dis[u[i]] + w[i])

//u[i]為第i條邊的起點,v[i]為第i條邊的終點,w[i]為第i條邊的權重(就是長度)

dis[v[i]] = dis[u[i]] + w[i]

最外層一共迴圈了n-1次,內迴圈迴圈了m次,

內迴圈的意思就是:通過每一條邊來鬆弛每兩個頂點之間的距離。

外迴圈n-1次的原因:因為在乙個包含n個頂點的圖中,任意兩點之間的最短路最多包含n-1條邊。

有些特別愛思考的同學又會發出乙個疑問:真的最多只能包含n-1條邊?最短路徑中不可能包含迴路麼?

答案是:不可能!最短路徑肯定是乙個不包含迴路的簡單路徑。迴路分為正權迴路(即迴路權值之和為正)和負權迴路(即迴路權值之和為負)。分別討論一下為什麼這兩種迴路都不可能有。如果最短路徑中包含正權迴路,那麼去掉這個迴路,一定可以得到更短的路徑。如果最短路徑中包含負權迴路,那麼肯定沒有最短路徑,因為每多走一次負權迴路就可以得到更短的路徑。因此,最短路徑肯定是乙個不包含迴路的簡單路徑,即最多包含n-1條邊,所以進行n-1輪鬆弛就可以了。

來個題實戰下:poj3259wormholes

#include

using

namespace

std;

int u[5400], v[5400], w[5400], dis[550];

int main()

for(int i = 2*m; i < 2*m+w; i++)

fill(dis, dis+540, 0x3f3f3f3f);

dis[1] = 0;

for(int i = 0; i < n-1; i++)

}if(!check)

break;

}bool flag = false;

for(int i = 0; i < 2*m+w; i++)

if(flag)//判斷是否存在負環,也就是說在進行n-1輪鬆弛後, 仍然可以繼續鬆弛成功,那麼此圖必然存在負權迴路。在之前證明中已經討論過,如果乙個圖沒有負權迴路,那麼最短路徑所包含的邊最多為n-1條,即進行n-1輪鬆弛之後最短路不會再發生變化。如果在n-1輪鬆弛之後最短路仍然會發生變化,則該圖必然存在負權迴路。

break;

}if(flag)

cout

<< "yes\n";

else

cout

<< "no\n";}}

return

0;}

bellman-ford的佇列優化解決:

每次僅對最短路程發生變化了的點的相鄰邊執行鬆弛操作。但是如何知道當前哪些點的最短路程發生了什麼變化呢?這裡可以用乙個佇列來維護這些點。

每次選取隊首頂點u(隨意命名的),對頂點u的所有出邊進行鬆弛操作。例如有一條u->v的邊,如果通過u->v這條邊是的源點到頂點v的最短路程變短(dis[u] + edge[u][v] < dis[v]),且頂點v不在當前佇列中,就將頂點v放入隊尾。需要注意的是,同乙個頂點同事在佇列中出現多次是毫無意義的,所以需要乙個標記陣列進行判重(判斷哪些點已經在佇列中)。在對頂點u的所有出邊鬆弛完畢之後,就將頂點u出隊。接下來不斷從佇列中取出隊首頂點再進行如上操作,直到佇列空為止。

判斷有無負環: 如果某個點進入佇列的次數超過n次則存在負環

#include

#include

#include

#include

using

namespace

std;

struct node

node(int a, int b)

};vector

a[505];

int dis[550], c[550];

bool vis[550];

int main()

for(int i = m*2; i < m*2 + w; i++)

fill(dis, dis+n +1, 0x3f3f3f3f);

dis[1] = 0;

memset(c, 0, sizeof(c));

memset(vis, false, sizeof(vis));

vis[1] = true;

int ok = 1;

c[1] = 1;

queue

q;q.push(1);

while(!q.empty())}}

if(ok == 0)

break;

}if(ok == 0)

cout

<< "yes\n";

else

cout

<< "no\n";}}

return

0;}

Bellman Ford 演算法及其優化

bellman ford 演算法及其優化 bellman ford 演算法與另乙個非常著名的 dijkstra 演算法一樣,用於求解單源點最短路徑問題。bellman ford 演算法除了可求解邊權均非負的問題外,還可以解決存在負權邊的問題 意義是什麼,好好思考 而 dijkstra 演算法只能處理...

Bellman Ford 演算法及其優化

bellman ford 演算法與另乙個非常著名的 dijkstra 演算法一樣,用於求解單源點最短路徑問題。bellman ford 演算法除了可求解邊權均非負的問題外,還可以解決存在負權邊的問題 意義是什麼,好好思考 而 dijkstra 演算法只能處理邊權非負的問題,因此 bellman fo...

Bellman Ford演算法,SPFA演算法

bellman ford 演算法能在更普遍的情況下 存在負權邊 解決單源點最短路徑問題。對於給定的帶權 有向或無向 圖g v,e 其源點為 s,加權函式w是 邊集e 的對映。對圖g執行 bellman ford 演算法的結果是乙個布林值,表明圖中是否存在著乙個從源點s 可達的負權迴路。若不存在這樣的...