Spfa模板(使用鄰接表和隊列實現)
全局準備工作
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函數
void addEdge(int src, int to, int weight)
{
Adj[nodeP].v = to;
Adj[nodeP].w = weight;
Adj[nodeP].next = head[src];
head[src] = nodeP++;
}
addEdge(a, b, w)作用是在數組Adj中留下一條記錄了去向和邊權的記錄,且其next指向表中相同src指向的下一個點,同時更新了head表頭
Spfa主體
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);
}
}
}
}
}
main中初始化
-
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要維護初始爲所有頂點的隊列。