貝爾曼(bellmanford)算法:node
大意:分爲兩步:1,對各邊進行鬆弛操做,即更新最短距離 2,判斷是否產生迴路web
Bellman-Ford算法的流程以下:
給定圖G(V, E)(其中V、E分別爲圖G的頂點集與邊集),源點s,
數組Distant[i]記錄從源點s到頂點i的路徑長度,初始化數組Distant[n]爲, Distant[s]爲0;算法
如下操做循環執行至多n-1次,n爲頂點數:
對於每一條邊e(u, v),若是Distant[u] + w(u, v)< Distant[v],則另Distant[v] = Distant[u]+w(u, v)。w(u, v)爲邊e(u,v)的權值;
若上述操做沒有對Distant進行更新,說明最短路徑已經查找完畢,或者部分點不可達,跳出循環。不然執行下次循環;
爲了檢測圖中是否存在負環路,即權值之和小於0的環路。對於每一條邊e(u, v),若是存在Distant[u] + w(u, v)< Distant[v]的邊,則圖中存在負環路,便是說改圖沒法求出單源最短路徑。不然數組Distant[n]中記錄的就是源點s到各頂點的最短路徑長度。
可知, Bellman-Ford算法 尋找單源最短路徑的時間複雜度爲O(V*E).數組
例子:ui
Descriptionthis
While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way path that delivers you to its destination at a time that is BEFORE you entered the wormhole! Each of FJ's farms comprises N (1 ≤ N ≤ 500) fields conveniently numbered 1..N, M (1 ≤ M ≤ 2500) paths, and W (1 ≤ W ≤ 200) wormholes.spa
As FJ is an avid time-traveling fan, he wants to do the following: start at some field, travel through some paths and wormholes, and return to the starting field a time before his initial departure. Perhaps he will be able to meet himself :) .code
To help FJ find out whether this is possible or not, he will supply you with complete maps to F (1 ≤ F ≤ 5) of his farms. No paths will take longer than 10,000 seconds to travel and no wormhole can bring FJ back in time by more than 10,000 seconds.orm
Inputip
Line 1: A single integer, F. F farm descriptions follow.
Line 1 of each farm: Three space-separated integers respectively: N, M, and W
Lines 2..M+1 of each farm: Three space-separated numbers (S, E, T) that describe, respectively: a bidirectional path between S and E that requires T seconds to traverse. Two fields might be connected by more than one path.
Lines M+2..M+W+1 of each farm: Three space-separated numbers (S, E, T) that describe, respectively: A one way path from S to E that also moves the traveler back T seconds.
Output
Lines 1..F: For each farm, output "YES" if FJ can achieve his goal, otherwise output "NO" (do not include the quotes).
Sample Input
2 3 3 1 1 2 2 1 3 4 2 3 1 3 1 3 3 2 1 1 2 3 2 3 4 3 1 8
Sample Output
NO YES
題目大意:
FJ童鞋家的農田裏面有若干個蟲洞,有一些蟲洞是相連的,能夠消耗一些時間爬過去(無向)。還有一些蟲洞比較特殊,從一頭爬到那一頭以後時間會退後一些(有向)
FJ但願經過爬蟲洞(?)來時時間退後,從而能看到另一個本身。根據輸入的蟲洞信息來判斷是否能夠實現FJ的願望。
code:
#include<stdio.h>
#define inf 999999
struct node
{
int u,v,w;
} edge[6000];
int dis[505];
int n,m,w,in;
void add(int u,int v,int c)
{
in++;
edge[in].u=u;
edge[in].v=v;
edge[in].w=c;
}
int bellman()
{
int u,v,w,i,j,flag;
for(i=1; i<=n; i++)//初始化
{
dis[i]=inf;
}
dis[1]=0;
flag=0;
for(i=1; i<=n; i++)//邊的鬆弛
{
for(j=1; j<=in; j++)
{
if(dis[edge[j].v]>dis[edge[j].u]+edge[j].w)
{
dis[edge[j].v]=dis[edge[j].u]+edge[j].w;
}
}
}
for(i=1; i<=in; i++)//判斷是否有迴路
if(dis[edge[i].v]>dis[edge[i].u]+edge[i].w)
return 1;
return 0;
}
int main()
{
int i,j,t,u,v,c;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&w);
in=0;
for(i=0; i<m; i++)
{
scanf("%d%d%d",&u,&v,&c);
add(u,v,c);
add(v,u,c);
}
for(i=0; i<w; i++)
{
scanf("%d%d%d",&u,&v,&c);
add(u,v,-1*c);
}
if(bellman())
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
Dijkstra算法和Bellman算法思想有很大的區別:
Dijkstra算法在求解過程當中,源點到集合S內各頂點的最短路徑一旦求出,則以後不變了,修改的僅僅是源點到T集合中各頂點的最短路徑長度。Bellman算法在求解過程當中,每次循環都要修改全部頂點的dist[],也就是說源點到各頂點最短路徑長度一直要到Bellman算法結束才肯定下來。
若是存在從源點可達的負權值迴路,則最短路徑不存在,由於能夠重複走這個迴路,使得路徑無窮小。
做爲一種單源最短路徑算法,Bellman-Ford對於有向圖和無向圖都能適用,它還有一個Dijkstra算法沒法具有的特色,那就是對含負權圖的最短路徑搜索。每i輪對邊的遍歷以後,只要不存在負權迴路,Bellman-Ford算法均可以保證得到距離源點i條邊的點的最短路徑。由於最短路徑的最大長度不會超過n條邊,n爲節點的數目。因此n次遍歷後全部的節點一定都能找到最短路徑。若是n次後還能夠繼續鬆弛,則代表該圖存在負權迴路,能夠對代碼稍做修改來計算負權環的大小。