Bellman-Ford 可解決帶有負權邊的最短路問題數組
解決負權邊和Dijkstra相比是一個優勢,Bellman-Ford的核心代碼只有4行::測試
u[],v[],w[] 分別存一條邊的頂點、權值,dis[]存從 1 源點到各個頂點的距離
優化
for(i=1;i<=n-1;i++) for(j=1;j<=m;j++) if(dis[v[j]] > dis[u[j]]+w[j]) dis[v[j]] = dis[u[j]]+w[j];
願過程:spa
循環n-1次,把每一個頂點每條邊都鬆弛;code
優化方法:blog
①,最壞的狀況就是循環了n-1次才求出到每一個頂點的最短路徑,若果在n-1次以前就已經所有鬆弛完成,那麼後面的循環就是多餘io
優化:class
for(k=1;k<=n-1;k++)//共有 n 個頂點,循環n-1次便可 { flag = 0; for(i=1;i<=m;i++)//對當前全部的邊進行鬆弛 { if(dis[v[i]] > dis[u[i]]+w[i]) { dis[v[i]] = dis[u[i]]+w[i]; flag = 1; } } if(flag == 0) break;//鬆弛也完成,結束 }
②,原過程:每次循環鬆弛事後,都有已經肯定了的源點到某點最短的路徑,此後這些頂點的最短路的值就會一直保持不變,再也不受後續鬆弛操做的影響,可是每次還要判斷是否須要鬆弛,這裏浪費了時間。循環
優化:肯定一條邊後總邊數減一,把不能進行本次鬆弛的邊再次後頭存到原數組,鬆弛成功的邊捨棄,再次鬆弛時只對未鬆弛的邊進行操做,m的值會隨着鬆弛預愈來愈小,直到所有完成。方法
for(k=1;k<=n-1;k++)//共有 n 個頂點,循環n-1次便可 { m = M;//從新賦值後的 m 是數組中存儲邊的條數 s = 1;flag = 0; for(i=1;i<=m;i++)//對當前全部的邊進行鬆弛 { if(dis[v[i]] > dis[u[i]]+w[i]) { dis[v[i]] = dis[u[i]]+w[i]; M--; //鬆弛成功,邊數減一 flag = 1; } else//把本次不能進行鬆弛的邊從新存儲到當前的數組 { u[s] = u[i]; v[s] = v[i]; w[s] = w[i]; s++; } } if(flag == 0) break;//鬆弛也完成,結束 }
附完整代碼:
#include <stdio.h> int main() { int dis[10],i,k,m,n,s=1,u[10],v[10],w[10],M,flag; int inf = 99999999; scanf("%d%d",&n,&m); M = m; for(i=1;i<=m;i++) { scanf("%d%d%d",&u[i],&v[i],&w[i]);//輸入各邊及權值 } for(i=1;i<=n;i++) { dis[i] = inf;//初始化爲正無窮 } dis[1] = 0;//以 1 爲源點 for(k=1;k<=n-1;k++)//共有 n 個頂點,循環n-1次便可 { m = M;//從新賦值後的 m 是數組中存儲邊的條數 s = 1;flag = 0; for(i=1;i<=m;i++)//對當前全部的邊進行鬆弛 { if(dis[v[i]] > dis[u[i]]+w[i]) { dis[v[i]] = dis[u[i]]+w[i]; M--; //鬆弛成功,邊數減一 flag = 1; } else//把本次不能進行鬆弛的邊從新存儲到當前的數組 { u[s] = u[i]; v[s] = v[i]; w[s] = w[i]; s++; } } if(flag == 0) break;//鬆弛也完成,結束 } for(i=1;i<=n;i++) { printf("%d ",dis[i]); } return 0; }
測試數據1:
5 5 2 3 2 1 2 -3 1 5 5 4 5 2 3 4 3
運行結果:
0 -3 -1 2 4
測試數據2:
5 7 1 2 2 1 5 10 2 3 3 2 5 7 3 4 4 4 5 5 5 3 6
運行結果:
0 2 5 9 9