上一期介紹到了SPFA算法,只是一筆帶過,這一期讓我們詳細的介紹一下SPFA。
1 SPFA原理介紹
SPFA算法和dijkstra算法特別像,總感覺自己講的不行,同學說我的博客很辣雞,推薦一個視頻講解,想看點這里,算法思路如下:
1)和dijkstra一樣初始化,定義一個dis[ ]數組,除了源點賦成0之外其它點都賦成正無窮,然后定義一個隊列q。
2)把隊列q的隊首元素取出,標志為不在隊中,將其作為中繼點對這個隊首元素的所有出邊進行松弛操作(不知道松弛操作請看這里),修改完dis值后,判斷每一個修改過dis值的元素是否在隊列q中,如果不在,就放入隊尾;然后判斷這個數入隊的次數,如果大於n(n為點的個數),那就說明出現了負權回路,算法結束,否則繼續。
3)不斷循環,直到隊列為空。
2 實現過程中的一些問題
- question:怎么標志出隊?
answer:可以定義一個vis[ ]數組,最開始全部為0,表示都不在隊列中,每入隊一個元素x,就把vis[x]賦成1,每出隊一個元素就賦值成0。
- question:怎么判斷一個數入隊次數?
answer:可以定義一個num[ ]數組,每入隊一個元素x,就num[x]++;這個可以不寫,因為題目一般不會出現負權回路。
- question:怎么判斷隊列為空?
answer:最流行的寫法是while(!q.empty()),但是不太好理解,我一般會寫成while(s.size()),和前一句意思相同。
3 圖解演示
//這個圖解做了一上午,可能講的不好,不喜勿噴
4 代碼奉上:
1 void SPFA() 2 { 3 for(int i=1;i<=n;i++) 4 dis[i]=inf; 5 queue<int>q; 6 q.push(1);vis[1]=1;dis[1]=0; 7 while(q.size()) 8 { 9 x=q.front();q.pop();vis[x]=0; 10 for(int i=head[x];i;i=a[i].next) 11 { 12 int s=a[i].to; 13 if(dis[s]>dis[x]+a[i].cost) 14 { 15 dis[s]=dis[x]+a[i].cost; 16 if(vis[s]==0) 17 { 18 vis[s]=1; 19 q.push(s); 20 } 21 } 22 } 23 } 24 }
5 算法優化
新更博客:SPFA算法優化