题目
Luogu
1
−
>
n
1->n
1−>n 最短路,可以多次经过终点,有
k
k
k 次边权取反操作,求最短路
思路
f
i
j
f_{ij}
fij:
i
,
j
i,j
i,j 的最短路
g
i
j
g_{ij}
gij:
i
,
j
i,j
i,j 用至多一次取反最短路
可以发现的是
g
g
g 数组当
i
≠
j
i\not=j
i=j 时显然会用一次取反
那么定义
h
u
k
h_{uk}
huk 表示
1
−
>
u
1->u
1−>u 用至多
k
k
k 次魔法的最短路
那么
h
u
,
0
=
f
1
,
u
h_{u,0}=f_{1,u}
hu,0=f1,u
f
u
,
1
=
g
1
,
u
f_{u,1}=g_{1,u}
fu,1=g1,u
转移如下:
h
u
,
k
=
m
i
n
{
h
v
,
k
−
1
+
g
v
,
u
}
h_{u,k}=min\{h_{v,k-1}+g_{v,u}\}
hu,k=min{hv,k−1+gv,u}
可以写成矩阵
(
h
1
,
k
,
h
2
,
k
,
.
.
.
,
h
n
k
)
∗
(
g
11
,
g
12
,
.
.
.
,
g
1
n
g
21
,
g
22
,
.
.
.
,
g
2
n
.
.
.
g
n
1
,
g
n
2
,
.
.
.
,
g
n
n
)
=
(
h
1
,
k
+
1
,
h
2
,
k
+
1
,
.
.
.
,
h
n
k
+
1
)
\left( \begin{matrix} h_{1,k},h_{2,k},...,h_{nk} \end{matrix} \right) * \left( \begin{matrix} g_{11},g_{12},...,g_{1n}\\ g_{21},g_{22},...,g_{2n}\\ ...\\ g_{n1},g_{n2},...,g_{nn} \end{matrix} \right)= \left( \begin{matrix} h_{1,k+1},h_{2,k+1},...,h_{nk+1} \end{matrix} \right)
(h1,k,h2,k,...,hnk)∗⎝⎜⎜⎛g11,g12,...,g1ng21,g22,...,g2n...gn1,gn2,...,gnn⎠⎟⎟⎞=(h1,k+1,h2,k+1,...,hnk+1)
记转移矩阵为
G
G
G 初始矩阵为
H
H
H 那么
H
′
=
H
∗
G
k
H'=H*G^{k}
H′=H∗Gk
类比一般的矩阵乘法 有
a
∗
(
b
+
c
)
=
a
∗
b
+
a
∗
c
a*(b+c)=a*b+a*c
a∗(b+c)=a∗b+a∗c
a
+
m
i
n
(
b
,
c
)
=
m
i
n
(
a
+
b
,
b
+
c
)
a+min(b,c)=min(a+b,b+c)
a+min(b,c)=min(a+b,b+c)
仍然有矩阵乘法的结合律
可以再推导一次
(
a
∗
b
)
×
(
b
∗
c
)
×
(
c
∗
d
)
(a*b)\times(b*c)\times(c*d)
(a∗b)×(b∗c)×(c∗d)
p
=
f
∗
g
,
q
=
g
∗
h
,
s
=
f
∗
g
∗
h
p=f*g,q=g*h,s=f*g*h
p=f∗g,q=g∗h,s=f∗g∗h
s i j = p ∗ h = m i n k = 1 c { p i k + h k j } = m i n k = 1 c { m i n l = 1 b { f i l + g l k } + h k j } = m i n k = 1 c { m i n l = 1 b { f i l + g l k + h k j } } = m i n l = 1 b { m i n k = 1 c { f i l + g l k + h k j } } = m i n l = 1 b { f i l + m i n k = 1 c { g l k + h k j } } = m i n k = 1 c { f i l + q l j } = f ∗ q s_{ij}=p*h=min_{k=1}^{c}\{p_{ik}+h_{kj}\} \\=min_{k=1}^{c}\{min_{l=1}^b\{f_{il}+g_{lk}\}+h_{kj}\} \\=min_{k=1}^{c}\{min_{l=1}^b\{f_{il}+g_{lk}+h_{kj}\}\} \\=min_{l=1}^b\{min_{k=1}^{c}\{f_{il}+g_{lk}+h_{kj}\}\} \\=min_{l=1}^b\{f_{il}+min_{k=1}^{c}\{g_{lk}+h_{kj}\}\} \\=min_{k=1}^{c}\{f_{il}+q_{lj}\}=f*q sij=p∗h=mink=1c{pik+hkj}=mink=1c{minl=1b{fil+glk}+hkj}=mink=1c{minl=1b{fil+glk+hkj}}=minl=1b{mink=1c{fil+glk+hkj}}=minl=1b{fil+mink=1c{glk+hkj}}=mink=1c{fil+qlj}=f∗q
代码
#include<set>
#include<map>
#include<stack>
#include<ctime>
#include<cstdio>
#include<queue>
#include<cmath>
#include<vector>
#include<cstring>
#include<climits>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
int read(){
int f=1,x=0;char c=getchar();
while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
return f*x;
}
#define MAXN 100
#define MAXM 2500
#define INF 10000000000000000ll
struct Matrix{
int r,c;
LL m[MAXN+5][MAXN+5];
void Init(int R,int C){
r=R,c=C;
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
m[i][j]=INF;
return ;
}
friend Matrix operator * (Matrix A,Matrix B){
Matrix C;
C.Init(A.r,B.c);
for(int i=1;i<=A.r;i++)
for(int j=1;j<=B.c;j++)
for(int k=1;k<=A.c;k++)
C.m[i][j]=min(C.m[i][j],A.m[i][k]+B.m[k][j]);
return C;
}
}A,B,C;
Matrix Pow(Matrix x,int y){
Matrix ret;
ret.Init(x.r,x.c);
for(int i=1;i<=x.r;i++)
ret.m[i][i]=0;
while(y){
if(y&1) ret=ret*x;
x=x*x,y>>=1;
}
return ret;
}
LL f[MAXN+5][MAXN+5],g[MAXN+5][MAXN+5];
void Floyd(int n){
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
return ;
}
struct Edge{
int u,v,w;
}edge[MAXM+5];
int main(){
int n=read(),m=read(),k=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i!=j)
f[i][j]=g[i][j]=INF;
else f[i][i]=0,g[i][i]=INF;
for(int i=1;i<=m;i++){
edge[i].u=read(),edge[i].v=read(),edge[i].w=read();
f[edge[i].u][edge[i].v]=edge[i].w;
}
Floyd(n);
for(int t=1;t<=m;t++){
int u=edge[t].u,v=edge[t].v;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
g[i][j]=min(g[i][j],f[i][u]-edge[t].w+f[v][j]);
}
A.Init(1,n),B.Init(n,n);
for(int j=1;j<=n;j++)
A.m[1][j]=f[1][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
B.m[i][j]=g[i][j];
C=A*Pow(B,k);
printf("%lld\n",C.m[1][n]);
return 0;
}