SPFA演算法及前向星優化

2021-06-17 15:28:28 字數 3336 閱讀 9696

分類: 其他

2010-11-21 22:29

191人閱讀收藏 

舉報演算法

優化output

algorithm

input儲存

先說說spfa演算法:

spfa演算法

來自"nocow"

演算法簡介

spfa(shortest path faster algorithm)是

bellman-ford演算法

的一種佇列

實現,減少了不必要的冗餘計算。也有人說spfa本來就是bellman-ford演算法,現在廣為流傳的

bellman-ford演算法

實際上是山寨版。

演算法流程

演算法大致流程是用乙個佇列來進行維護。初始時將源加入佇列。每次從佇列中取出乙個元素,並對所有與他相鄰的點進行

鬆弛,若某個相鄰的點鬆弛成功,則將其入隊。直到隊列為空時演算法結束。

這個演算法,簡單的說就是佇列優化的bellman-ford,利用了每個點不會更新次數太多的特點發明的此演算法

spfa——shortest path faster algorithm,它可以在o(ke)的時間複雜度內求出源點到其他所有點的最短路徑,可以處理負邊。spfa的實現甚至比dijkstra或者bellman_ford還要簡單:

設dist代表s到i點的當前最短距離,fa代表s到i的當前最短路徑中i點之前的乙個點的編號。開始時dist全部為+∞,只有dist[s]=0,fa全部為0。

維護乙個佇列,裡面存放所有需要進行迭代的點。初始時佇列中只有乙個點s。用乙個布林陣列記錄每個點是否處在佇列中。

每次迭代,取出隊頭的點v,依次列舉從v出發的邊v->u,設邊的長度為len,判斷dist[v]+len是否小於dist[u],若小於則改進dist[u],將fa[u]記為v,並且由於s到u的最短距離變小了,有可能u可以改進其它的點,所以若u不在佇列中,就將它放入隊尾。這樣一直迭代下去直到佇列變空,也就是s到所有的最短距離都確定下來,結束演算法。若乙個點入隊次數超過n,則有負權環。

接下來是前向星:

前向星優化

[cpp]view plain

copy

不要把前向星想成什麼高深莫測的東西……它其實就是一種鄰接表的緊縮儲存形式。  

為什麼叫前向星?因為它是將邊按照前端點排序,並用乙個陣列k[i]記錄端點i第一次以左端點出現的位置。這樣,我們就能用o(e)的空間複雜度儲存下乙個鄰接表,而避免了鍊錶或n^2的龐大空間消耗。  

當然,實際上我們並不需要排序:因為我們只需要知道某一條邊應該放到什麼位置即可。因而我們還需要乙個陣列t[i]儲存從i出發的邊的條數。則需要儲存在的位置就可以很輕易地求得。(詳見**,以usaco中的butter為例)  

butter題目**如下:program butter(input,output);  

type  

edge=record  

x,y,d:longint;  

end;  

var  

min,res,n,p,c,x,y,i,j,l,r:longint;  

te,e:array[0..3000] of edge;  

tk,t,k,num,d:array[1..800] of longint;  

q:array[1..100000] of longint;  

use:array[1..800] of boolean;  

procedure swap(var n1,n2:longint);  

var  

tmp:longint;  

begin  

tmp:=n1;n1:=n2;n2:=tmp;  

end;  

begin  

assign(input,'butter.in'

);reset(input);  

readln(n,p,c);  

fori:=1 to n 

dobegin  

read(x);  

inc(num[x]);  

end;  

fori:=1 to c 

dobegin  

with e[i*2-1] do

readln(x,y,d);  

e[i*2]:=e[i*2-1];  

swap(e[i*2].x,e[i*2].y);  

end;  

c:=c*2;  

fori:=1 to c 

doinc(t[e[i].x]);  

j:=0;k[1]:=1;  

fori:=2 to p 

dok[i]:=k[i-1]+t[i-1];  

tk:=k;te:=e;  

fori:=1 to c 

dobegin  

e[tk[te[i].x]]:=te[i];  

inc(tk[te[i].x]);  

end;  

min:=maxlongint;  

fori:=1 to p 

dobegin  

fillchar(q,sizeof

(q),0);  

fillchar(d,sizeof

(d),127);  

fillchar(use,sizeof

(use),

false

);  

q[1]:=i;l:=1;r:=1;d[i]:=0;use[i]:=true

;  repeat  

forj:=k[q[l]] to k[q[l]]+t[q[l]]-1 

doif

d[q[l]]+e[j].d

begin  

d[e[j].y]:=d[q[l]]+e[j].d;  

ifnot use[e[j].y] then  

begin  

use[e[j].y]:=true

;  inc(r);  

q[r]:=e[j].y;  

end;  

end;  

use[q[l]]:=false

;  inc(l);  

until l>r;  

res:=0;  

forj:=1 to p 

dores:=res+d[j]*num[j];  

ifres

end;  

assign(output,'butter.out'

);rewrite(output);  

writeln(min);close(output);  

end.  

最短路(SPFA 前向星

problem description 輸入t,n分別代表有t條通道,和n個地點。接下來t行u,v,w分別表示u地點於v地點之間通道消費,有重複邊 sample input 5 51 2 20 2 3 30 3 4 20 4 5 20 1 5 100 sample output 運用spfa的幾個要...

C 最短路 spfa 前向星

time limit 7000ms memory limit 65536k 有疑問?點這裡 給出乙個帶權無向圖,包含n個點,m條邊。求出s,e的最短路。保證最短路存在。多組輸入。對於每組資料。第一行輸入n,m 1 n n 5 10 5,1 m m 2 10 6 接下來m行,每行三個整數,u,v,w,...

暢通工程續(SPFA 鏈式前向星)

傳送門 hdu 1874 某省自從實行了很多年的暢通工程計畫後,終於修建了很多路。不過路多了也不好,每次要從乙個城鎮到另乙個城鎮時,都有許多種道路方案可以選擇,而某些方案要比另一些方案行走的距離要短很多。這讓行人很困擾。現在,已知起點和終點,請你計算出要從起點到終點,最短需要行走多少距離。本題目包含...