最短路算法

最短路算法

http://hi.baidu.com/mfs666/blog/item/20d12b732800ba1b8601b07c.html

最短路算法就是在图中某点到其他点或者所有点对间的最短带权距离,这个应用可能比较多。因为除了直接的应用,可以建图。可以把某些元素看做点,把转变的代价作为边,也可以用。也可以把关键点用最短路做成更小的图,然后用较少的搜索来满足特殊要求(见某搜索题)。

program shortestpaths;
const maxn=500;
var
i,j,n,k,t,y:longint;
m,dist1:array[0..maxn,0..maxn] of longint;//邻接矩阵和floyd区
dist2,dist3,p1,p2,p3:array[0..maxn] of longint;//dijkstra区和SPFA区
b:array[0..maxn] of record n:longint;l,h:array[0..maxn] of longint; end;//边表

procedure dijkstra(x:longint);//迪杰克斯特拉算法,与普利姆很相似
var
   i,j,t,mm:longint;
   f:array[0..maxn] of boolean;//更新标志
begin
   fillchar(f,sizeof(f),false);//标志初始化
   for i:=1 to n do begin //距离初始话,如果没有直接的路,值就是maxlongint
    dist2[i]:=m[x,i];
    p1[i]:=x;
   end;
   dist2[x]:=0;//源点置0
   p1[x]:=x;
   f[x]:=true;//源点设置为已更新
   for i:=1 to n-1 do begin//对除源点外的点进行更新
    mm:=maxlongint;//最小值初始化
    for j:=1 to n do
     if (not f[j]) and (dist2[j]<mm) then begin//寻找距离最小且未更新的点
      mm:=dist2[j];
      t:=j;
     end;
    f[t]:=true;//将选出得点设置为已更新
    for j:=1 to n do
     if dist2[t]+m[t,j]<dist2[j] then begin//松弛
      dist2[j]:=dist2[t]+m[t,j];
      p1[j]:=t;//更新路径上的前一个点
     end;
   end;
end;

procedure spfa(x:longint);//死皮法
var
   f:array[0..maxn] of boolean;//入队标志
   q:array[0..maxn] of longint;//队
   i,j,t,s,e,d:longint;
begin
   fillchar(q,sizeof(q),0);//初始化队
   fillchar(f,sizeof(f),false);//初始化入队标志
   for i:=1 to n do
    dist3[i]:=maxlongint;//所有点初始化为maxlongint,只有源点为0不同于dij
   dist3[x]:=0;
   s:=0;e:=0;//对指针初始化
   inc(s);q[s]:=x;f[x]:=true;//源点入队,此时不考虑循环,加1即可
   while not (s=e) do begin//如果队不空(首<>尾)
    e:=(e+1) mod n;出队指针(加1modn循环)
    d:=q[e];//出队
    f[d]:=false;//出队标志
    for i:=1 to b[d].n do
     if dist3[d]+b[d].l[i]<dist3[b[d].h[i]] then begin//对相邻点进行松弛
      dist3[b[d].h[i]]:=dist3[d]+b[d].l[i];
      p2[b[d].h[i]]:=d;//保存路径
      if not f[i] then begin//如果 不在队中 则入队
       s:=(s+1) mod n;
       q[s]:=i;
       f[i]:=true;
      end;
     end;
   end;
end;

begin
assign(input,'vijos.in');reset(input);
readln(n);
for i:=1 to n do
   for j:=1 to n do begin
    read(m[i,j]);
    inc(b[i].n);
    b[i].h[b[i].n]:=j;
    b[i].l[b[i].n]:=m[i,j];
end;
readln(y);
dist1:=m;

for k:=1 to n do//这一段是基本floyd,先枚举中间点
   for i:=1 to n do//再枚举两端点
    for j:=1 to n do begin
     t:=dist1[i,k]+dist1[k,j];//松弛,若通过中心点更近,则更新
     if t<dist1[i,j] then begin
      dist1[i,j]:=t;p2[k]:=i;p2[j]:=k;保存路径
    end;
spfa(y);
dijkstra(y);
for i:=1 to n do
   writeln(dist1[y,i],' ',dist2[i],' ',dist3[i]);
i:=6;
while p1[i]<>y do begin
   writeln(p1[i]);
   i:=p1[i];
end;

end.

posted @ 2010-05-14 13:47  jesonpeng  阅读(191)  评论(0)    收藏  举报