bellman-ford演算法能解決負權邊的圖,就是說能夠來判斷存在負環。
先來看一下核心**:
最外層一共迴圈了n-1次,內迴圈迴圈了m次,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次的原因:因為在乙個包含n個頂點的圖中,任意兩點之間的最短路最多包含n-1條邊。
有些特別愛思考的同學又會發出乙個疑問:真的最多只能包含n-1條邊?最短路徑中不可能包含迴路麼?
答案是:不可能!最短路徑肯定是乙個不包含迴路的簡單路徑。迴路分為正權迴路(即迴路權值之和為正)和負權迴路(即迴路權值之和為負)。分別討論一下為什麼這兩種迴路都不可能有。如果最短路徑中包含正權迴路,那麼去掉這個迴路,一定可以得到更短的路徑。如果最短路徑中包含負權迴路,那麼肯定沒有最短路徑,因為每多走一次負權迴路就可以得到更短的路徑。因此,最短路徑肯定是乙個不包含迴路的簡單路徑,即最多包含n-1條邊,所以進行n-1輪鬆弛就可以了。
來個題實戰下:poj3259wormholes
bellman-ford的佇列優化解決:#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;}
每次僅對最短路程發生變化了的點的相鄰邊執行鬆弛操作。但是如何知道當前哪些點的最短路程發生了什麼變化呢?這裡可以用乙個佇列來維護這些點。
每次選取隊首頂點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 可達的負權迴路。若不存在這樣的...