Skip to content

k短路 $ O(n^3logk) $ ​

  • $ 定义d_{k,i,j} 为经过了k条边的i到j的最短路 $
  • $ 转移方程:d_{a+b,i,j}=min(d_{a,i,k}+d_{b,k,j}) $
  • 暴力转移时间复杂度:$ O(k^2n^3) $
  • 考虑倍增与快速幂的思想,将k分离成$ 2^0+2^1... $
  • 只不过此时快速幂的两数相乘,变成两个数组跑floyd
  • 时间复杂度: $ O(n^3logk) $
cpp
int n,m,k,S,E;
int adj[N][N],tmp[N][N],res[N][N];
void mul(int c[][N],int a[][N],int b[][N]){
	memset(tmp,0x3f,sizeof tmp);
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++)tmp[i][j]=min(tmp[i][j],a[i][k]+b[k][j]);
		}
	}
	memcpy(c,tmp,sizeof tmp);
}
void qpow(){
	memset(res,0x3f,sizeof res);
	for(int i=1;i<=n;i++)res[i][i]=0;
	for(;k;k>>=1){
		if(k&1)mul(res,res,adj);
		mul(adj,adj,adj);
	}
}
void solve(){
	cin>>k>>m>>S>>E;
	memset(adj,0x3f,sizeof adj);
	map<int,int> ids;
	if(!ids.count(S))ids[S]=++n;
	if(!ids.count(E))ids[E]=++n;
	S=ids[S],E=ids[E];
	while(m--){
		int u,v,w;
		cin>>w>>u>>v;
		if(!ids.count(u))ids[u]=++n;
		if(!ids.count(v))ids[v]=++n;
		u=ids[u],v=ids[v];
		adj[u][v]=adj[v][u]=min(adj[u][v],w);
	}
	qpow();
	cout<<res[S][E]<<"\n";
}