P4568 JLOI 飞行路线 分层最短路板子
luogu SuperJvRuo的图
各层内部正常连边,各层之间从上到下连权值为0的边。每向下跑一层,就相当于免费搭一次飞机。跑一遍从\(s\)到\(t+n∗k\)的最短路即可。
#include<cstdio>
#include<queue>
#include<iostream>
#include<cstring>
#define maxn 5000005
#define maxm 1000005
using namespace std;
int n,m,k,s,t,tot,ans = 0x7777777f,head[maxn],dis[maxn];
bool vis[maxn];
inline int read() {
int x = 0,f = 1; char s = getchar();
while(s < '0' || s > '9') {if(s == '-') f = -1;s = getchar();}
while(s >= '0' && s <= '9') {x = x * 10 + s - '0';s = getchar();}
return f * x;
}
inline int min(int a,int b){return a < b ? a : b;}
struct edge{
int to,next,dis;
}e[maxm<<3];
struct node{
int val,id;
};
inline bool operator<(node x,node y){return x.val > y.val;}
inline void add(int u,int v,int val){
e[++tot].to = v;
e[tot].dis = val;
e[tot].next = head[u];
head[u] = tot;
}
inline void dijkstra(int s) {//堆优化 dijkstra
memset(dis, 0x7f, sizeof (dis));
priority_queue<node> q;
dis[s] = 0;
q.push((node) { 0, s });
while(!q.empty()) {
int u = q.top().id;
q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (int v, w, i = head[u]; v = e[i].to, w = e[i].dis, i; i = e[i].next)
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
if (!vis[v]) q.push((node) { dis[v], v });
}
}
}
int main(){
n=read();m=read();k=read();s=read();t=read();
s ++,t ++;
int u,v,w;
for(int i = 1;i <= m;i++){
u=read();v=read();w=read();
++ u; ++ v;
add(u,v,w); add(v,u,w);
for(int j = 1;j <= k;j++){
add(u + (j - 1) * n, v + j * n, 0), add(v + (j - 1) * n, u + j * n, 0);
//层与层之间对应的点连一条权值为 0 的边
add(u + j * n, v + j * n, w), add(v + j * n, u + j * n, w);}
//每一层中对应的点连边
}
dijkstra(s);
for(int i = 0;i <= k;i++) ans = min(ans,dis[t + i*n]);
printf("%d\n",ans);
return 0;
}