题目大意:有t(t<=100)条无向边连接两点,求s到e刚好经过n(n<=10^7)条路径的最小距离。
第一反应分层图,但是一看n就懵逼了,不会写。看了题解之后才知道可以这么玩。。。
首先有100条边最多200个点,但点编号到1000,所以离散化一下。
任何一个正整数都能用2的幂相加得到,所以先把n转变成2进制来看,按位考虑。dist[i][j][k]表示刚好经过2^i条边从j到k的最短距离,则dist[i,j,k]=min{dist[i-1][j][l]+dist[i-1][l][k]}。用类似快速幂的方法,若是2进制的n这一位是1的话,就把答案数组g和dist跑floyd(min{g[i-1][j][l]+dist[i-1][l][k]}),否则dist自己和自己跑(min{dist[i-1][j][l]+dist[i-1][l][k]}),这样子g就是跑n条路径得出的最小距离了。
代码如下:
type map=array[1..1000,1..1000]of longint; var n,t,s,e,i,j,k,len,x,y,tot:longint; c,d,g:array[1..1000,1..1000]of longint; num:array[1..1000]of longint; procedure merge(var a,b:map); var i,j,k:longint; begin fillchar(c,sizeof(c),63); for k:=1 to tot do for i:=1 to tot do for j:=1 to tot do if c[i,j]>a[i,k]+b[k,j] then c[i,j]:=a[i,k]+b[k,j]; a:=c; end; procedure work; begin fillchar(g,sizeof(g),63); for i:=1 to tot do g[i,i]:=0; while n>0 do begin if n and 1=1 then merge(g,d); merge(d,d); n:=n>>1; end; writeln(g[num[s],num[e]]); end; begin readln(n,t,s,e); fillchar(d,sizeof(d),63); for i:=1 to t do begin readln(len,x,y); if num[x]=0 then begin inc(tot);num[x]:=tot; end; if num[y]=0 then begin inc(tot);num[y]:=tot; end; d[num[x],num[y]]:=len;d[num[y],num[x]]:=len; end; work; end.
时间: 2024-10-21 21:00:43