SPFA算法
2010-09-24 20:14 snowkylin 阅读(451) 评论(0) 编辑 收藏 举报program spfa; const max=10000; type nodep=^node; node=record data,wei:longint; next:nodep; end; var g:array[1..max]of nodep; n,i,st:longint; p:nodep; dist:array[1..max]of longint; procedure init; var i,e,x,y,z:longint; p:nodep; begin readln(n,e); fillchar(g,sizeof(g),0); for i:=1 to e do begin readln(x,y,z); if g[x]=nil then begin new(g[x]); g[x]^.data:=y; g[x]^.wei:=z; g[x]^.next:=nil; end else begin new(p); p^.data:=y; p^.wei:=z; p^.next:=g[x]; g[x]:=p; end; if g[y]=nil then begin new(g[y]); g[y]^.data:=x; g[y]^.wei:=z; g[y]^.next:=nil; end else begin new(p); p^.data:=x; p^.wei:=z; p^.next:=g[y]; g[y]:=p; end; end; readln(st); end; procedure solve; var i,front,rear,k,u:longint; q:array[0..max-1]of longint; inq:array[1..max]of boolean; begin for i:=1 to n do dist[i]:=maxlongint; dist[st]:=0; front:=0; rear:=1; q[1]:=st; fillchar(inq,sizeof(inq),false); inq[st]:=true; while front<>rear do begin front:=(front+1)mod max; inq[st]:=false; k:=q[front]; p:=g[k]; while (p<>nil) do begin u:=p^.data; if (dist[k]+p^.wei<dist[u]) then begin dist[u]:=dist[k]+p^.wei; if not inq[u] then begin rear:=(rear+1)mod max; q[rear]:=u; end; end; p:=p^.next; end; end; end; begin assign(input,'spfa.in'); reset(input); assign(output,'spfa.out'); rewrite(output); init; solve; for i:=1 to n do write(dist[i],' '); close(input); close(output); end. 输入文件: 7 8 1 2 6 1 4 5 1 6 8 2 3 3 3 5 4 4 3 2 4 6 4 5 7 1 1
松弛:
if (dist[k]+p^.w<dist[u]) then dist[u]:=dist[k]+p^.w;
就是如果 从原点到点u(泛指所有与k相连的点)的距离+u到k的距离 小于 原来“预测”的点k到原点距离,就更新。形状如把直线拉成折线,故称松弛。
只要u点被松弛了,就可能从u点经过再得到新的最短路径,所以加入队列。
program spfa; const max=10000; type nodep=^node; node=record data:longint;{from the n of a[n] to "data"} w:longint;{the distance between point"n" to point"data"} next:nodep; end; var g:array[1..max]of nodep; dist:array[1..max]of longint; i,n,e,st{the start point}:longint; procedure init; var i,x,y,z:longint; p:nodep; begin readln(n,e); fillchar(g,sizeof(g),0); for i:=1 to e do begin readln(x,y,z); if g[x]=nil then begin new(g[x]); g[x]^.data:=y; g[x]^.w:=z; g[x]^.next:=nil; end else begin new(p); p^.data:=y; p^.w:=z; p^.next:=nil; p^.next:=g[x]; g[x]:=p; end; if g[y]=nil then begin new(g[y]); g[y]^.data:=x; g[y]^.w:=z; g[y]^.next:=nil; end else begin new(p); p^.data:=x; p^.w:=z; p^.next:=nil; p^.next:=g[y]; g[y]:=p; end; end; readln(st); end; procedure solve; var inq:array[1..max]of boolean;{find if n is in queue"q"} q:array[1..max]of longint; i,front,rear,k,u:longint; p:nodep; begin for i:=1 to n do dist[i]:=maxlongint; dist[st]:=0; front:=0; rear:=1; q[1]:=st; fillchar(inq,sizeof(inq),false); inq[st]:=true; while front<>rear do begin front:=(front+1)mod max; inq[st]:=false; k:=q[front];{pick out the front of "q"queue in k} p:=g[k];{the point linked to k,next use all of the point in p to do the "relaxation"} while (p<>nil) do begin u:=p^.data;{pick out the point linked to k} if (dist[k]+p^.w<dist[u]) then begin dist[u]:=dist[k]+p^.w; if not inq[u] then begin rear:=(rear+1)mod max; q[rear]:=u; end; end; p:=p^.next;{relax next point} end; end; end; begin while not eof do begin init; solve; for i:=1 to n do writeln(dist[i]); end; end.