分层图最短路
思想和应用
当遇到一些需要对边权进行操作的题目时,我们可以建立一些分层图,分别对边权进行修改然后再跑最短路等等来解决问题
思路
完全是一个裸题,由于\(k\)的范围较少,所以可以建出\(k+1\)个分层图,分别代表将\(0\)条,\(1\)条......\(k\)条边的边权变为\(0\)。然后再跑一遍\(Dijkstra\),总时间复杂度为\(O(k*(mlog_2m))\)。
Code
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#define ll long long
using namespace std;
const int N=10005,M=100005;
int n,m,k,s,t,tot,ans=2147483647;
int head[N*22],edge[M*22],Nxt[M*22],ver[M*22],d[N*22];
bool v[N*22];
priority_queue < pair <int,int> > q;
void add(int x,int y,int z){
ver[++tot]=y;
edge[tot]=z;
Nxt[tot]=head[x];
head[x]=tot;
}
void dijkstra(int ss){
for(int i=0;i<=N*20;i++){
d[i]=2147483647;
}
d[ss]=0;
q.push(make_pair(0,ss));
while(!q.empty()){
int x=q.top().second;
q.pop();
if(v[x]) continue;
v[x]=1;
for(int i=head[x];i;i=Nxt[i]){
int y=ver[i],z=edge[i];
if(d[y]>d[x]+z){
d[y]=d[x]+z;
q.push(make_pair(-d[y],y));
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
scanf("%d%d",&s,&t);
s++,t++;
for(int i=1,x,y,z;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
x++,y++;
add(x,y,z);
add(y,x,z);
for(int j=1;j<=k;j++){
add(x+j*n,y+j*n,z);
add(y+j*n,x+j*n,z);//每一层上单独建图
add(x+(j-1)*n,y+j*n,0);
add(y+(j-1)*n,x+j*n,0);//层与层之间
}
}
dijkstra(s);
for(int i=0;i<=k;i++){
ans=min(ans,d[i*n+t]);//每一层的终点都有可能成为最终的答案
}
printf("%d\n",ans);
return 0;
}