分层图最短路,主要是用来求解允许少量次数修改边权的最短路问题,由于修改此数较小,所以解法也有些许暴力.下面,让我们来看这么一道例题:
description:
有一(n)点(m)边构成的连通图,给定起点(S)和终点(T),现允许你将至多(k(kleq10))条边的边权修改为(0),请你求出修改次数不超过(k)的情况下,(S)到(T)的最短路径长度.
solution:
此题是分层图最短路模板题.首先不难想到一一枚举(k)条免费边,然后跑最短路,但算法复杂度(O((m+n)logn cdot C_{m}^{k})),极度暴力,连最小数据范围都十分吃力,于是我们便需引入新的思路.
由于(k)较小,我们不妨构造(k+1)个相同的联通图,其中第(i)到(i+1)个连通图中对应的边我们连上权值为(0)的单向边,以表示免费的边.用此方式,每次只能跑向层数更高的图,或在本层图内跑.且每跑进一个新图,意味着我们跑过了一条免费边,所以构造该分层图可以完美求解本题.答案即为每层终点的最短路的最小值,为方便起见,我们可以在每层终点向下一层终点连一条权值为(0)的单向边以传递最短路,最后输出最后一层终点的答案即可.
code:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>
#define R register
#define next kdjadskfj
#define debug puts("mlg")
#define mod 1004535809
#define Mod(x) ((x%mod+mod)%mod)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
inline ll read();
inline void write(ll x);
inline void writeln(ll x);
inline void writesp(ll x);
ll n,m,k;
ll head[3000000],next[3000000],to[3000000],w[3000000],tot;
ll S,T;
ll d[3000000];
bool vis[3000000];
inline void add(ll x,ll y,ll z){to[++tot]=y;next[tot]=head[x];head[x]=tot;w[tot]=z;}
//queue<ll>q;
//inline void spfa(){
// memset(d,0x3f,sizeof d);
// q.push(S);d[S]=0;
// while(q.size()){
// ll x=q.front();q.pop();vis[x]=false;
// for(R ll i=head[x],ver;i;i=next[i]){
// ver=to[i];
// if(d[ver]>d[x]+w[i]){
// d[ver]=d[x]+w[i];
// if(!vis[ver]){
// vis[ver]=true;
// q.push(ver);
// }
// }
// }
// }
//}
ll ans;
priority_queue<pair<ll,ll> >q;
inline void dijkstra(){
memset(d,0x3f,sizeof d);
d[S]=0;;
q.push(make_pair(0,S));
while(q.size()){
ll x=q.top().second;q.pop();
if(vis[x]) continue;
vis[x]=true;
for(R ll i=head[x],ver;i;i=next[i]){
ver=to[i];
if(d[ver]>d[x]+w[i]){
d[ver]=d[x]+w[i];
q.push(make_pair(-d[ver],ver));
}
}
}
}
int main(){
n=read();m=read();k=read();
S=read()+1;T=read()+1;
while(m--){
ll x=read()+1,y=read()+1,z=read();
add(x,y,z);add(y,x,z);
for(R ll i=1;i<=k;i++){
add(x+i*n,y+i*n,z);add(y+i*n,x+i*n,z);
add(x+(i-1)*n,(y+i*n),0);
add(y+(i-1)*n,(x+i*n),0);
}
}
for(R ll i=1;i<=k;i++){
add(T+(i-1)*n,T+i*n,0);
}
// spfa();
dijkstra();
writeln(d[T+n*k]);
}