bzoj 3245 spfa

题意:n个点,编号为0~n-1,m条有向边,限速不为0的边按照限速前进,限速为0的边按进入这条道路时的速度前进(即到该条边起点的速度),给定终点,初始起点为点0,初始速度为70,问从点0到终点最快时间的路径

可以理解成拆点的spfa

dis[i,j]表示到达第i个点的速度为j,spfa更新时讨论该边的速度是否为0分别按两种方法更新

每次更新dis[i,j]时,记录转移来的点和转移来的速度注意并不是入队的时候才更新,并且要两个都记录,只记录转移来的点的话会出事情...mdzz

var
        n,m,st,x,y,z,w  :longint;
        minn,l,tot      :longint;
        i               :longint;
        ans             :double;
        pre,other,len,v :array[0..50010] of longint;
        dis             :array[0..200,0..510] of double;
        vis             :array[0..200,0..510] of boolean;
        que             :array[0..75010,0..1] of longint;
        last,way        :array[0..200] of longint;
        fromn,fromv     :array[0..200,0..510] of longint;
procedure connect(x,y,vv,z:longint);
begin
   inc(l);
   pre[l]:=last[x];
   last[x]:=l;
   other[l]:=y;
   len[l]:=z;
   v[l]:=vv;
end;

procedure spfa;
var
        h,tmp,tl,cur,p,q:longint;
begin
   fillchar(dis,sizeof(dis),127);
   h:=0; tl:=1;
   que[1,0]:=1; que[1,1]:=70;
   dis[1,70]:=0;
   while (h<>tl) do
   begin
      h:=h mod 75005+1;
      cur:=que[h,0]; tmp:=que[h,1];
      vis[cur,tmp]:=false;
      q:=last[cur];
      while (q<>0) do
      begin
         p:=other[q];
         if v[q]=0 then
         begin
            if dis[p,tmp]>dis[cur,tmp]+len[q]/tmp then
            begin
               dis[p,tmp]:=dis[cur,tmp]+len[q]/tmp;
               fromn[p,tmp]:=cur;
               fromv[p,tmp]:=tmp;
               if not vis[p,tmp] then
               begin
                  vis[p,tmp]:=true;
                  tl:=tl mod 75005+1;
                  que[tl,0]:=p;
                  que[tl,1]:=tmp;
               end;
            end;
         end else
         begin
            if dis[p,v[q]]>dis[cur,tmp]+len[q]/v[q] then
            begin
               dis[p,v[q]]:=dis[cur,tmp]+len[q]/v[q];
               fromv[p,v[q]]:=tmp;
               fromn[p,v[q]]:=cur;
               if not vis[p,v[q]] then
               begin
                  vis[p,v[q]]:=true;
                  tl:=tl mod 75005+1;
                  que[tl,0]:=p;
                  que[tl,1]:=v[q];
               end;
            end;
         end;
         q:=pre[q];
      end;
   end;
end;

procedure print(x,v:longint);
var
        y,xx:longint;
        i:longint;
begin
   tot:=0;  xx:=x;
   while (x<>-1) do
   begin
      inc(tot);
      way[tot]:=x;
      x:=fromn[xx,v];
      v:=fromv[xx,v];
      xx:=x;
   end;
   for i:=tot downto 2 do write(way[i]-1,' ');
   writeln(way[1]-1);
end;

begin
   read(n,m,st); inc(st);
   for i:=1 to m do
   begin
      read(x,y,z,w);
      connect(x+1,y+1,z,w);
   end;
   fillchar(fromn,sizeof(fromn),255);
   spfa;
   ans:=maxlongint;
   for i:=0 to 500 do
     if dis[st,i]<ans then
     begin
        ans:=dis[st,i];
        minn:=i;
     end;
   print(st,minn);
end.
——by Eirlys

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值