题目大意很简单:给出一个无向图,求两个点之间的经过k条边的最短路(边可以重复经过)
最多只有100条边,但是k高达10^6。
可以用 类bellman ford的方法,将边迭代n次
(与bellman ford不同的是,每一次迭代都必须选边,不过spfa无法保证每一条边都取);
这样的复杂的事o(ne)的 ,已经有10^8,而且中间还涉及大量的数组滚动,要ac还是太难了。
于是,一种奇异的算法出现了——矩阵乘法;
如果我们用邻接矩阵存好走k条边的距离之后,与贮存了边的邻接矩阵相称,得到的矩阵就是走k+1条边的距离,
只要把这里的矩阵相乘的方式改为——a[ i , j ]:=min(b [ i,k]+b [ k , j ]),即乘法改为加法,加法改为取min
由于加法和min满足结合率,可以直接快速幂了,复杂度是100^3 * log(10^6).
program lmd; var i,j,k,n,maxn,x,y,z,t,s,e:longint; mul,now,ans:array[1..1000,1..1000]of longint; hash:array[1..1000]of longint; yes:array[1..1000]of boolean; a:array[0..100+5]of record x,y,z:longint; end; begin assign(input,'3613.in'); assign(output,'3613.out'); reset(input);rewrite(output); read(n,t,s,e); fillchar(yes,sizeof(yes),false); maxn:=0; for i:=1 to t do begin read(a[i].z,a[i].x,a[i].y); yes[a[i].x]:=true; yes[a[i].y]:=true; end; maxn:=0; for i:=1 to 1000 do if yes[i] then begin inc(maxn); hash[i]:= maxn; end; for i:=1 to maxn do for j:=1 to maxn do begin mul[i,j]:=maxlongint shr 1; ans[i,j]:=maxlongint shr 1; end; for i:=1 to t do begin mul[hash[a[i].x],hash[a[i].y]]:=a[i].z; mul[hash[a[i].y],hash[a[i].x]]:=a[i].z; end; for i:=1 to maxn do ans[i,i]:=0; while n>0 do begin if n and 1=1 then begin for i:=1 to maxn do for j:=1 to maxn do begin now[i,j]:=ans[i,j]; ans[i,j]:=maxlongint shr 1; end; for i:=1 to maxn do for j:=1 to maxn do for k:=1 to maxn do if ans[i,j]>now[i,k]+mul[k,j] then ans[i,j]:=now[i,k]+mul[k,j]; end; for i:=1 to maxn do for j:=1 to maxn do now[i,j]:=maxlongint shr 1; for i:=1 to maxn do for j:=1 to maxn do for k:=1 to maxn do if now[i,j]>mul[i,k]+mul[k,j] then now[i,j]:=mul[i,k]+mul[k,j]; for i:=1 to maxn do for j:=1 to maxn do mul[i,j]:=now[i,j]; n:=n shr 1; end; write(ans[hash[s],hash[e]]); close(input);close(output); end.