spfa算法:ios
大意:咱們記源點爲S,由源點到達點i的「當前最短路徑」爲D[i],開始時將全部D[i]初始化爲無窮大,D[S]則初始化爲0。算法所要作的,就是在運行過程當中,不斷嘗試減少D[]數組的元素,最終將其中 每個元素減少到實際的最短路徑。
過程當中,咱們要維護一個隊列,開始時將源點置於隊首,而後反覆進行這樣的操做,直到隊列爲空:
(1)從隊首取出一個結點u,掃描全部由u結點能夠一步到達的結點,具體的掃描過程,隨存儲方式的不一樣而不一樣;
(2)一旦發現有這樣一個結點,記爲v,知足D[v] > D[u] + w(u, v),則將D[v]的值減少,減少到和D[u] + w(u, v)相等。其中,w(u, v)爲圖中的邊u-v的長度,因爲u-v必相鄰,因此這個長度必定已知(否則咱們獲得的也不叫一個完整的圖);這種操做叫作鬆弛。
(3)上一步中,咱們認爲咱們「改進了」結點v的最短路徑,結點v的當前路徑長度D[v]相比於之前減少了一些,因而,與v相連的一些結點的路徑長度可能會相應地減少。注意,是可能,而不是必定。但即便如此,咱們仍然要將v加入到隊列中等待處理,以保證這些結點的路徑值在算法結束時被降至最優web
例題:算法
B - Wormholes
Crawling in process... Crawling failed Time Limit:2000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u
Submit Status
Description數組
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.ui
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 :) .this
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.spa
Inputcode
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.
Outputorm
Lines 1..F: For each farm, output "YES" if FJ can achieve his goal, otherwise output "NO" (do not include the quotes).
Sample Inputhtm
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 8Sample Output
NO
YESHint
For farm 1, FJ cannot travel back in time.
For farm 2, FJ could travel back in time by the cycle 1->2->3->1, arriving back at his starting location 1 second before he leaves. He could start from anywhere on the cycle to accomplish this.
題目大意:
FJ童鞋家的農田裏面有若干個蟲洞,有一些蟲洞是相連的,能夠消耗一些時間爬過去(無向)。還有一些蟲洞比較特殊,從一頭爬到那一頭以後時間會退後一些(有向)
FJ但願經過爬蟲洞(?)來時時間退後,從而能看到另一個本身。根據輸入的蟲洞信息來判斷是否能夠實現FJ的願望。
code:
#include<iostream> #include<stdio.h> #include<algorithm> #include<string.h> #include<queue> using namespace std; #define INF 999999 int cnt[5505]; int visit[5505],dis[5505]; int n,m,w,edges[5505][5505]; void SPFA() { int i,t,flag; queue<int>q; for(i=1; i<=n; i++) { dis[i]=INF; visit[i]=0; cnt[i]=0; } q.push(1); visit[1]=1; dis[1]=0; cnt[1]++; flag=0; while(q.empty()==0) { t=q.front(); q.pop(); visit[t]=0; for(i=1; i<=n; i++) if(edges[t][i]!=0&&i!=t) if(dis[i]>dis[t]+edges[t][i]) { dis[i]=dis[t]+edges[t][i]; if(visit[i]==0) { q.push(i); visit[i]=1; cnt[i]++; if(cnt[i]>n) { flag=1; break; } } } if(flag==1) break; } if(flag==1) cout<<"YES"<<endl; else cout<<"NO"<<endl; } int main() { int f,i,j,k,s,e,t; scanf("%d",&f); for(i=1;i<=f;i++) { scanf("%d %d %d",&n,&m,&w); for(j=1; j<=n; j++) for(k=1; k<=n; k++) edges[j][k]=INF; for(j=1;j<=m;j++) { scanf("%d %d %d",&s,&e,&t); if(t<edges[s][e]) edges[s][e]=edges[e][s]=t; } for(j=1;j<=w;j++) { scanf("%d %d %d",&s,&e,&t); edges[s][e]=-t; } SPFA(); } return 0; }
對SPFA的一個很直觀的理解就是由無權圖的BFS轉化而來。在無權圖中,BFS首先到達的頂點所經歷的路徑必定是最短路(也就是通過的最少頂點數),因此此時利用數組記錄節點訪問可使每一個頂點只進隊一次,但在帶權圖中,最早到達的頂點所計算出來的路徑不必定是最短路。一個解決方法是放棄數組,此時所需時間天然就是指數級的,因此咱們不能放棄數組,而是在處理一個已經在隊列中且當前所得的路徑比原來更好的頂點時,直接更新最優解。