1. 程式人生 > >SPFA 最短路演算法 及求負環(POJ3259)

SPFA 最短路演算法 及求負環(POJ3259)

什麼是 SPFA

Bellman-ford的佇列優化,即SPFA

  1. 本質思想:每次從佇列中取出一個點,利用這個點出發的所有邊更新所有的終點距離,若更新成功,且被更新的點不在佇列裡,就把它放入佇列。
  2. 實現:佇列初始只放第一個點,也是用一個dis陣列,然後跑個不停。再用一個布林陣列記錄一個點在不在佇列裡。
  3. 若一個點入隊了大於N次,則存在負環。
  4. 一般不會用鄰接矩陣寫……但也可以用

上傳一張大佬圖解

上傳一張大佬圖解SPFA
附上大佬部落格連結:SPFA.
題意:有 f 個農場,每個農場有 n 塊地,其間有 m 條路,w條時光隧道,過去的時候時間會倒退 t 秒。判斷是否可以從某塊地出發後又回來,看到了離開之前的自己。
注意:前m條路為雙向邊,時空隧道為單向邊。
方法:Floyd或者SPFA判斷是否存在負權環。

AC程式碼

#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#define inf 0x3f3f3f3f
#define N 502 
using namespace std;

int n, m, w, Map[N][N];

int dis[N];
bool vis[N];

bool spfa(int x){
	///Shortest Path Faster Algorithm 
vis[x] = true; dis[x] = 0; int cnt[N] = {0}; queue<int> q; q.push(x); while(!q.empty()){ int t = q.front(); q.pop(); cnt[t]++; if(cnt[t] > n) return true; vis[t] = false; for(int i = 1; i <= n; i++){ if(dis[i] > dis[t] + Map[t][i]){ dis[i] = dis[t] + Map[t][i]
; if(!vis[i]){ vis[i] = true; q.push(i); } } } } return false; } void init(int n){ for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) { Map[i][j] = inf; } for(int i = 1; i <= n; i++){ dis[i] = inf; vis[i] = false; } } int main() { int u,v,w_; int t; ios::sync_with_stdio(false); cin >> t; while(t--){ cin >> n >> m >> w; init(n); for(int i = 0; i < m; i++){ cin >> u >> v >> w_; if(Map[u][v] > w_) Map[u][v] = Map[v][u] = w_; } for(int i = 0; i < w; i++){ cin >> u >>v >> w_; Map[u][v] = -w_; } if(spfa(1)) cout << "YES" <<endl; else cout << "NO" << endl; } return 0; }

下面說一下我今天一上午做這道題遇到的問題

  1. 鄰接矩陣大法好,因為要判斷重邊,鄰接表不好判斷重邊
  2. 出佇列標記vis為未訪問,進棧標記為訪問
  3. 疏鬆原理更新各個點到終點的距離
  4. 最最坑的編譯器問題,用了學校的電腦,被設定了某種許可權,使測試結果與樣例結果不符,讓我一直懷疑人生 ,關愛生命,從使用自己電腦開始