最短路5解

题目模板:最短路

https://www.luogu.org/problem/show?pid=3371

千年不过的不用指针的spfa;
原来各位dalao是骗我的!
根本不用ff数组来判重!
加上这题目pas题解比较少就来谈谈5种AC的思路(顺便总结一下);
①floyd算法 时间:O(n^3);空间:O(n^2);
对于20%的数据:N<=5,M<=15
对于40%的数据:N<=100,M<=10000

②dijkstra算法
时间: O(n^2); 空间:O(n^2);
对于70%的数据:N<=1000,M<=100000

uses math; 
const maxn=5000;
var g:array[1..maxn,1..maxn] of longint;
    d:array[1..maxn] of longint; //pre[i]指最短路径上I的前驱结点
    n,m,s,x,y,w,i,j:longint;
procedure dijkstra(v0:longint);
 var u:array[1..maxn] of boolean;
     i,j,k:longint; min:longint;
begin
  fillchar(u,sizeof(u),false);
  for i:=1 to n do d[i]:=g[v0,i];
  d[v0]:=0;
  u[v0]:=true;
  for i:=1 to n-1 do begin   //每循环一次加入一个离1集合最近的结点并调整其他结点的参数
    min:=2147483647; k:=0; //k记录离1集合最近的结点
    for j:=1 to n do
      if (not u[j]) and (d[j]<min) then begin
        k:=j; min:=d[j];
    end;
    if k=0 then break;
    u[k]:=true;
    for j:=1 to n do
      if (not u[j]) and (g[k,j]+d[k]<d[j]) then d[j]:=g[k,j]+d[k];
  end;
end;
begin
  readln(n,m,s);
  for i:=1 to n do
    for j:=1 to n do if i=j then g[i,j]:=0 else g[i,j]:=2147483647;
  for i:=1 to m do begin
    readln(x,y,w);
    g[x,y]:=min(w,g[x,y]);
  end;
  dijkstra(s);      //找出最短路径
  for i:=1 to n do write(d[i],' ');
  writeln;
end.

③dijkstra+前向星空间优化+堆优化
时间: O(n log n); 空间:O(kn);
对于100%的数据:N<=10000,M<=500000

type rec=record
 pre,en,w:longint;
end;
rec2=record
 id,val:longint;
end;
const inf=233333333;
      maxm=500000;
      maxn=10000;
var i,j,n,m,s,x,y,z,tot,nd:longint;
    d,head:array[-maxn..maxn]of longint;
    a:array[-maxm..maxm]of rec;
    dui:array[0..4*maxm]of rec2;
procedure swap(var a,b:rec2);
var t:rec2;
begin
 t:=a; a:=b; b:=t;
end;
procedure adde(u,v,w:longint);
begin
 inc(tot); a[tot].en:=v;
 a[tot].pre:=head[u];
 head[u]:=tot;
 a[tot].w:=w;
end;
procedure swap(var a,b:longint);
var t:longint;
begin t:=a;a:=b;b:=t;end;
procedure up(x:longint);//将一个结点“上浮”
begin
  while x>1 do begin //没有上浮到最顶层
    if dui[x].val>dui[x div 2].val then break;//如果上方的结点小于此节点,则暂停上浮
    swap(dui[x],dui[x div 2]);//交换上方结点与此结点
    x:=x div 2;
  end;
end;
procedure down(x:longint);//将一个节点“下沉”
  var y:longint;
begin
  while x<nd do begin
    y:=x+x;//y是x的左儿子
    if y>nd then break;//x已经沉到底部
    if (y<nd)and(dui[y+1].val<dui[y].val) then inc(y);//如果x存在右儿子,且右儿子比左儿子小,则将y赋值到右儿子
    if dui[x].val<=dui[y].val then break;//若两个儿子中的较小值仍然比x大,则停止下沉
    swap(dui[x],dui[y]);//下沉
    x:=y;
  end;
end;
function pop():longint;
begin
  pop:=dui[1].id;
  swap(dui[1],dui[nd]);//将最后的结点(保证其没有儿子)与最顶端交换
  dec(nd);
  down(1);//下沉顶端
end;
procedure dijkstra(v0:longint);
var i,j,k,minn,u,v,p:longint;
    vis:array[-maxn..maxn]of boolean;
begin
 fillchar(vis,sizeof(vis),false);
 for i:=1 to n do d[i]:=inf;
 d[v0]:=0;
 dui[1].val:=0;
 dui[1].id:=v0;
 nd:=1;
 for i:=1 to n do begin
  u:=pop();
  while vis[u] and (nd>0) do u:=pop();
  vis[u]:=true;
  p:=head[u];
  while p>0 do begin
   v:=a[p].en;
   if (not vis[v]) and(d[u]+a[p].w<d[v]) then begin
    d[v]:=d[u]+a[p].w;
    inc(nd);
    dui[nd].id:=v;
    dui[nd].val:=d[v];
    up(nd);
   end;
   p:=a[p].pre;
  end;
 end;
end;
begin
 readln(n,m,s);
 for i:=1 to m do begin
  readln(x,y,z);
  adde(x,y,z);
 end;
 dijkstra(s);
 for i:=1 to n do
 if d[i]=inf then write(2147483647,' ')else write(d[i],' ');
 writeln;

④ spfa队列优化+指针邻接表空间优化
时间: O(KE); 空间:O(KE);
对于100%的数据:N<=10000,M<=500000;

type pp=^node;
      node=record
      en,w:longint;
      pre:pp;
      end;
const maxn=50040;
var dis:array[0..maxn]of longint;
    a:array[0..maxn]of pp;
    n,m,b,u,v,x,y,i,j,l,w,s:longint;
procedure adde(u,v,w:longint);
var p:pp;
begin
 new(p);
 p^.pre:=a[u]^.pre;
 p^.en:=v; p^.w:=w;
 a[u]^.pre:=p;
end;
procedure spfa;
var f:array[0..maxn]of boolean;
    q:array[0..4*maxn]of longint;
    p:pp;
    head,tail,u,v:longint;
begin
 q[1]:=s; dis[s]:=0;
 head:=0; tail:=1;
 fillchar(f,sizeof(f),false);
 while head<tail do begin
  inc(head); u:=q[head]; p:=a[u];
  while p^.pre<>nil do begin
   p:=p^.pre; v:=p^.en; w:=p^.w;
   if dis[v]>dis[u]+w then begin
    dis[v]:=dis[u]+w;
    if not f[v] then begin
     f[v]:=true;
     inc(tail); q[tail]:=v;
    end;
   end;
  end;
  f[u]:=false;
 end;
end;
begin
 readln(n,m,s);
 for i:=1 to n do begin
  new(a[i]);
  a[i]^.pre:=nil;
 end;
 for i:=1 to m do begin
  readln(u,v,w);
  adde(u,v,w);
 end;
  for i:=1 to n do
  dis[i]:=maxlongint div 3;
 spfa;
// writeln;
 for i:=1 to n do
  if dis[i]=maxlongint div 3 then write('2147483647 ')
  else write(dis[i],' ');
 close(input);
 close(output);
end.

⑤ spfa队列优化+链式前向星空间优化
时间: O(KE); 空间:O(KE);
对于100%的数据:N<=10000,M<=500000

type rec=record
 w,en,pre:longint;
end;
var n,m,s,x,y,z,tot,i:longint;
    head,q,d:array[1..1000000]of longint;
    a:array[1..1000000]of rec;
procedure adde(u,v,w:longint);
begin
 inc(tot);
 a[tot].en:=v;
 a[tot].pre:=head[u];
 a[tot].w:=w;
 head[u]:=tot;
end;
procedure spfa;
var h,t,i,v,u:longint;
begin
 for i:=1 to n do d[i]:=maxlongint;
 q[1]:=s; d[s]:=0;
 h:=0; t:=1;
 while h<t do begin
  inc(h);
  u:=q[h];
  i:=head[u];
  while i>0 do begin
   v:=a[i].en;
   if d[v]=maxlongint then begin
    d[v]:=d[u]+a[i].w;
    inc(t);q[t]:=v;
   end else
   if d[v]-d[u]>a[i].w then begin
    inc(t);q[t]:=v;
    d[v]:=a[i].w+d[u];
   end;
   i:=a[i].pre;
  end;
 end;
end;
begin
 readln(n,m,s);
 for i:=1 to m do begin
  readln(x,y,z);
  adde(x,y,z);
 end;
 spfa;
 for i:=1 to n do
  if d[i]=maxlongint then write('2147483647 ')
  else write(d[i],' ');
end.

 

转载于:https://www.cnblogs.com/ljc20020730/p/7622200.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值