#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
int N,T,S,E,num;
map<int,int> mp;
struct Matrix{
int ma[210][210];
void clear(){
memset(ma,0x3f,sizeof(ma)); //初始化一定要大,否则WA
}
};
Matrix Floyd(Matrix a,Matrix b){
Matrix dis;
dis.clear();
int i,j,k;
for(k=1;k<=num;k++) //一次floyd 是找到一个中间点
for(i=1;i<=num;i++)
for(j=1;j<=num;j++)
if(dis.ma[i][j]>a.ma[i][k]+b.ma[k][j])
dis.ma[i][j]=a.ma[i][k]+b.ma[k][j];
return dis;
}
Matrix Solve(Matrix a,int k){
Matrix ans=a;
while(k){
if(k&1){
ans=Floyd(ans,a);
}
a=Floyd(a,a);
k>>=1;
}
return ans;
}
int main(){
//freopen("input.txt","r",stdin);
Matrix a;
while(~scanf("%d%d%d%d",&N,&T,&S,&E)){
num=0;
mp.clear();
a.clear();
int u,v,w;
while(T--){
scanf("%d%d%d",&w,&u,&v);
if(mp[u]==0)
mp[u]=++num;
if(mp[v]==0)
mp[v]=++num;
if(a.ma[mp[u]][mp[v]]>w)
a.ma[mp[u]][mp[v]]=a.ma[mp[v]][mp[u]]=w;
}
a=Solve(a,N-1); // N 条边 ,经过 N-1 个点
printf("%d\n",a.ma[mp[S]][mp[E]]);
}
return 0;
}
我们知道线性代数中有:
在只 含有 01邻接矩阵
A的
K次 方
C=A^K,
C[i][j]表示
i点到
j点正好经过
K条边的路径数。
而floyd则是每次使用一个中间点k去更新i,j之间的距离,那么更新成功表示i,j之间恰有一个点k时的最短路,如果做N - 1次floyd那么不就是i,j之间借助N - 1 个点时的最短路了
当 c[i][j] > a[i][k] + a[k][j] 则更新
第二次将c[i][j]拷贝回到a[i][j]当中,并将c[i][j]重新置为INF,再做一次,则是在原来的基础上在i,j之间再用一个点k来松弛,这时候i,j之间实际上已经是两个点了,
但是这个题的 n (边数太大)我们要用到 倍增法,其实即使 二分思想 例如 经过 5 条边 把 (4 个点) == 两个 2 条边的 松驰一次 ;