analysis
这是一个没有见过的模式:
- 特征
- 求S到E恰好走过N条边的最短路
- 点数少到可以用邻接矩阵存
- 解法
Floyd+矩阵快速幂
首先,若邻接矩阵A表示了两点间走过1条边的最短路,B表示了两点间走过2条边的最短路
那么有关系:
B [ i ] [ j ] = m i n ( A [ i ] [ k ] + A [ k ] [ j ] ) ( 1 < = k < = n ) B[i][j]=min(A[i][k]+A[k][j])(1<=k<=n) B[i][j]=min(A[i][k]+A[k][j])(1<=k<=n)
这样的话,我们继续推广这个关系可以得到:
若邻接矩阵A表示了两点间走过x条边的最短路,B表示了两点间走过k条边的最短路,C表示了两点间走过t条边的最短路,且k=x+t
那么:
B [ i ] [ j ] = m i n ( A [ i ] [ k ] + C [ k ] [ j ] ) ( 1 < = k < = n ) B[i][j]=min(A[i][k]+C[k][j])(1<=k<=n) B[i][j]=min(A[i][k]+C[k][j])(1<=k<=n)
如果我们换个方式写,设 A i A^i Ai邻接矩阵保存的是走过i条边后的两点之间的最短距离的话,那么
A i + j [ x ] [ y ] = m i n ( A i [ x ] [ k ] + A j [ k ] [ y ] ) A^{i+j}[x][y]=min(A^i[x][k] + A^j[k][y]) Ai+j[x][y]=min(Ai[x][k]+Aj[k][y])
最后的答案就是
A n [ S ] [ E ] A^n[S][E] An[S][E]
问题就转化为了:快速求出 A n A^n An数组
观察上面推广的式子,我们可以发现:
定义新运算"广义矩阵乘法"为
A i [ x ] [ y ] × A j [ x ] [ y ] = A i + j [ x ] [ y ] = m i n ( A i [ x ] [ k ] + A j [ k ] [ y ] ) A^{i}[x][y]\times A^{j}[x][y]=A^{i+j}[x][y]=min(A^i[x][k] + A^j[k][y]) Ai[x][y]×Aj[x][y]=Ai+j[x][y]=min(Ai[x][k]+Aj[k][y])
那么"广义矩阵乘法"满足结合律,也就是说:
( A i × A j ) × A k = A i × ( A j × A k ) (A^i\times A^j)\times A^k=A^i\times (A^j\times A^k) (Ai×Aj)×Ak=Ai×(Aj×Ak)
那么就可以对n进行二进制拆分, A n A^n An就可以像快速幂一样在logn的时间里求出来了
code
#include<bits/stdc++.h>
using namespace std;
#define loop(i,start,end) for(register int i=start;i<=end;++i)
#define anti_loop(i,start,end) for(register int i=start;i>=end;--i)
#define clean(arry,num) memset(arry,num,sizeof(arry))
#define ll long long
#define copy(arry1,arry2) memcpy(arry1,arry2,sizeof(arry1))
template<typename T>void read(T &x){
x=0;char r=getchar();T neg=1;
while(r>'9'||r<'0'){if(r=='-')neg=-1;r=getchar();}
while(r>='0'&&r<='9'){x=(x<<1)+(x<<3)+r-'0';r=getchar();}
x*=neg;
}
int T;
const int maxt=100+10;
int n;
const int maxn=1e6+10;
int nfp=0,S,E;
int G[maxt<<1][maxt<<1];
struct martix{
int G[maxt<<1][maxt<<1];
void clear_(){
loop(i,1,200){
loop(j,1,200){
G[i][j]=0x3f3f3f3f;
}
}
}
void print_(int len){
loop(i,1,len){
loop(j,1,len){
printf("%d ",G[i][j]);
}
printf("\n");
}
printf("\n");
}
};
inline martix mutply(martix A,martix B,int len){
martix ans;
ans.clear_();
loop(i,1,len){
loop(j,1,len){
loop(k,1,len)
ans.G[i][j]=min(A.G[i][k]+B.G[k][j],ans.G[i][j]);
}
}
return ans;
}
martix res;
martix sta;
inline void fastpower(int len,int t){
--t;
copy(res.G,G);
copy(sta.G,G);
//res.print_(len);
//sta.print_(len);
while(t){
if(t&1){
res=mutply(sta,res,len);
//res.print_(len);
}
t>>=1;
sta=mutply(sta,sta,len);
//sta.print_(len);
}
}
struct road{
int xi;
int yi;
int wi;
}line[maxt];
map<int,int>M;
int main(){
#ifndef ONLINE_JUDGE
freopen("datain.txt","r",stdin);
#endif
read(n);
read(T);
read(S);
read(E);
loop(i,1,T){
read(line[i].wi);
read(line[i].xi);
read(line[i].yi);
if(M[line[i].xi]==0)
M[line[i].xi]=++nfp;
if(M[line[i].yi]==0)
M[line[i].yi]=++nfp;
}
clean(G,0x3f);
loop(i,1,T)
G[M[line[i].yi]][M[line[i].xi]]=G[M[line[i].xi]][M[line[i].yi]]=line[i].wi;
fastpower(nfp,n);
printf("%d\n",res.G[M[S]][M[E]]);
return 0;
}