bzoj 1706 倍增floyd

题意:给定一张无向图,求从s到e恰好经过n条边的最短路

倍增floyd

Floyd是通过插入点的方法来找到最短路的,很适合此题,跑n遍floyd的就可以了

显然这样做是T的

我们将n进行二进制拆分,类似于快速幂的思想

map[p][i][j]表示刚好经过2^p条边从j到k的最短距离,

易知 map[p][i][j]=min{map[p-1][i][j]+map[p-1][i][j]}。

若n and 1 =1,则让答案数组f和map跑floyd(即 min{g[p-1][i][k]+map[p-1][k][j]}),

否则map自己和自己跑(min{map[p-1][i][k]+dist[p-1][k][j]})

更新n n=n >>1

非正常人类的编号我们只需要离散化一下就可以了

注意答案数组f的初始化同floyd,但map数组的初始化中 map[i,i]<>0 ,因为如果等于0的话它相当于停在那里并没有多一条边

初始化为(maxlongint div 10)居然废了,fillchar(63)就过了,mdzz,害我改了一个多小时


type
        rec=array[0..110,0..110] of longint;
var
        n,m,s,t,num,x,y,len:longint;
        map,f,c            :rec;
        vis                :array[0..1010] of longint;
        i,j                :longint;
function min (a,b:longint):longint;
begin
   if a0) do
   begin
      if (x and 1=1) then floyd(f,map);
      floyd(map,map);
      x:=x >>1;
   end;
end;

begin
   read(n,m,s,t);
   num:=0;
   fillchar(map,sizeof(map),63);
   fillchar(f,sizeof(f),63);
   for i:=1 to m do
   begin
      read(len,x,y);
      if vis[x]=0 then
      begin
         inc(num); vis[x]:=num;
      end;
      if vis[y]=0 then
      begin
         inc(num); vis[y]:=num;
      end;
      map[vis[x],vis[y]]:=len;
      map[vis[y],vis[x]]:=len;
   end;
   for i:=1 to num do f[i,i]:=0;
   work(n);
   writeln(f[vis[s],vis[t]]);
end.


—— by Eirlys








你可能感兴趣的:(bzoj,模板,floyd)