一個我認為比較好的Spfa模板(使用鄰接表和佇列實現)
阿新 • • 發佈:2019-02-10
全域性準備工作
int N, X; //N為點數 X為源點
int head[MAXN]; //head[src]表示以head為出發點的鄰接表表頭在陣列Adj中的位置,開始時所有元素初始化為-1
int nodeP; //在鄰接表和指向表頭的head陣列中定位用的記錄指標,開始時初始化為0
int dist[MAXN]; //儲存到源節點的距離,在Spfa()中初始化
bool vis[MAXN]; //這裡vis作inqueue解釋會更好,出於習慣使用了vis來命名,在Spfa()中初始化
Node定義struct Node {
int v, w, next;
}Adj[MAXM];
v即vertex,這裡意思相當於被指向的點to,w相當於weight,代表邊權,next用來指向在Adj中下一個從相同src出發的邊指向的點
addEdge函式addEdge(a, b, w)作用是在陣列Adj中留下一條記錄了去向和邊權的記錄,且其next指向表中相同src指向的下一個點,同時更新了head表頭 Spfa主體void addEdge(int src, int to, int weight) { Adj[nodeP].v = to; Adj[nodeP].w = weight; Adj[nodeP].next = head[src]; head[src] = nodeP++; }
main中初始化void Spfa() { queue<int> que; int i; for(i = 1; i <= N; i++) { dist[i] = NIL; vis[i] = false; } dist[X] = 0; //X為源點 que.push(X); while(!que.empty()) { int now = que.front(); que.pop(); vis[now] = false; //從queue中退出 //遍歷鄰接表 for(i = head[now]; i != -1; i = Adj[i].next) { //在Adj中,相同src出發指向的頂點為從head[src]開始的一項,逐項使用next尋找下去,直到找到第一個被輸 //入的項,其next值為-1 int to = Adj[i].v; if(dist[to] == NIL || dist[to] > dist[now] + Adj[i].w) { //鬆弛(RELAX)操作 dist[to] = dist[now] + Adj[i].w; if(!vis[to]) { //若被搜尋到的節點不在佇列que中,則把to加入到佇列中去 vis[to] = true; que.push(to); } } } } }
int main()
{
memset(head, -1, sizeof(head));
...
while(...) {
cin >> a >> b >> c;
addEdge(a, b, c);
}
Spfa();
//結果已經儲存在dist陣列中
return 0;
}
有些人以為這個演算法是Dijkstra,事實上Spfa和Dijkstra很像,只是他們維護的佇列不同,Spfa維護的是一個初始只有源節點的佇列,而Dijkstra要維護初始為所有頂點的佇列。