ssl2510/bzoj 1706 奶牛接力 矩阵乘法
题目大意
给一个无向图,给定起点(s)和终点(e),要走过t条边(t给定)(可以重复走)。求从起点到终点经过t条边的最短路。
分析
我们先从动态规划开始想,很容易就可以推出一条状态转移方程:
F[I,j]=min(f[i-1,k]+g[k,j])(1<=k<=n) (1<=i<=t)
其中,f[I,j]表示经过i条边到达点j的最短路径,N为顶点数,若点k,j间有边,G[k,j]为边权,否则为maxlongint。
但是这个动态规划的时间复杂度是O(t*n*n),题目中t<=1,000,000,n<=100。所以会超时。
所以我们要用矩阵乘法来做此题。建立一个邻接矩阵A,其中A[I,j]表示从i点到j点走一条边的最短路径。现在要走t条边,从一般的思路来看应该是求A^t然后再处理一下,但这题显然不能这么干(虽然我也不知道为什么是显然)。
那能否修改矩阵乘法?能!
可以从那一条状态转移方程找到灵感,把原本是c[i,j]=sum(a[i,k]*b[k,j]),现在改成c[i,j]=min(a[i,k]+b[k,j])且(0<a[i,k],0<b[k,j])。(具体为什么不想打字了,自己举例手算一下就知道了)。
然后用新的矩阵乘法(矩阵加法)来求A^t,输出(a[s,e])即可。
Ps:输入的点要离散。
type arr=array[1..110,1..110] of longint; var a,c:arr; b:array[1..10000] of longint; tot:longint; i,j,k,l:longint; n,m,x,y:longint; function cheng(x,x1:arr):arr; var i,j,k:longint; begin fillchar(cheng,sizeof(cheng),0); for i:=1 to tot do for j:=1 to tot do begin cheng[i,j]:=maxlongint div 3; for k:=1 to tot do if (x[i,k]<maxlongint) and (x1[k,j]<maxlongint) then if cheng[i,j]>x[i,k]+x1[k,j] then cheng[i,j]:=x[i,k]+x1[k,j]; end; end; procedure seach(n:longint); var i,j,k:longint; begin if n=1 then exit; seach(n div 2); c:=cheng(c,c); if n mod 2=1 then c:=cheng(c,a); end; begin readln(n,m,x,y); fillchar(b,sizeof(b),0); for i:=1 to 110 do for j:=1 to 110 do a[i,j]:=maxlongint; for i:=1 to m do begin readln(l,j,k); if b[j]=0 then begin tot:=tot+1; b[j]:=tot; end; if b[k]=0 then begin tot:=tot+1; b[k]:=tot; end; a[b[j],b[k]]:=l; a[b[k],b[j]]:=l; end; c:=a; seach(n); write(c[b[x],b[y]]); end.