题目大意
给一个无向图,给定起点(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.