题意:给定一张无向图,求从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.