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;
}
posted @ 2020-07-28 15:32  INFP  阅读(106)  评论(1编辑  收藏  举报