SPFA算法
2010-09-24 20:14 snowkylin 阅读(471) 评论(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.
浙公网安备 33010602011771号