题目描述
小 Z 打算在国庆假期期间搭乘旅游巴士去一处他向往已久的景点旅游。
旅游景点的地图共有 n 处地点,在这些地点之间连有 m 条道路。其中 1 号地点为景区入口,n 号地点为景区出口。我们把一天当中景区开门营业的时间记为 0 时刻,则
从 0 时刻起,每间隔 k 单位时间便有一辆旅游巴士到达景区入口,同时有一辆旅游巴士从景区出口驶离景区。
所有道路均只能单向通行 。对于每条道路,游客步行通过的用时均为恰好 1 单位时间。
小 Z 希望乘坐旅游巴士到达景区入口,并沿着自己选择的任意路径走到景区出口,再乘坐旅游巴士离开,这意味着他到达和离开景区的时间都必须是 k 的非负整数倍 。由
于节假日客流众多,小Z在坐旅游巴士离开景区前只想一直沿着景区道路移动, 而不想在任何地点(包括景区入口和出口) 或者道路上逗留 。
出发前,小 Z 忽然得知:景区采取了限制客流的方法,对于每条道路均设置了一个“开放时间”ai,游客只有不早于ai时刻才能通过这条道路。
请你帮助小 Z 设计一个旅游方案,使得他乘坐旅游巴士离开景区的时间尽量地早。
输入
输入的第一行包含 3 个正整数 n, m, k,表示旅游景点的地点数、道路数,以及旅游巴士的发车间隔。
输入的接下来 m 行,每行包含 3 个非负整数 ui, vi, ai,表示第 i 条道路从地点 ui出发,到达地点 vi,道路的“开放时间”为 ai。
输出
输出一行,仅包含一个整数,表示小 Z 最早乘坐旅游巴士离开景区的时刻。如果不存在符合要求的旅游方案,输出 ‐1。
样例
样例输入
5 5 3
1 2 0
2 5 1
1 3 0
3 4 3
4 5 1
样例输出
6
提示
【样例解释】
小 Z 可以在 3 时刻到达景区入口,沿 1 → 3 → 4 → 5 的顺序走到景区出口,并在6 时刻离开。
【数据范围】
对于所有测试数据有:2 ≤ n ≤ 1e4,1 ≤ m ≤ 2 × 1e
4,1 ≤ k ≤ 100,1 ≤ ui, vi ≤ n,0 ≤ ai ≤ 1e6。
分析
n为1e4,k为100,可以考虑分层图
由于到达终点的时刻为k的非负整数倍,所以将每个点拆成k个点,dist[i][j]
表示到达i号点的总用时 t
满足 t % k == j
的最小花费
分层跑最短路,设当前层数为u,则穿过这条边后层数转移到第 (u + 1) % k
层,取min即可
对于限制ai,由于中途不可以停留,所以我们可以在起点位置延后出发若干个k
然后跑dijkstra即可,时间复杂度为O(nklog(nk))
代码
#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N = 1e4 + 10,M = 2e4 + 10,K = 100 + 10,INF = 0x3f3f3f3f;
int n,m,k;
int h[N],e[M],a[M],ne[M],idx;
bool st[N][K];
int dist[N][K];
int ceil(int x,int m){
return (x - 1) / m + 1;
}
void add(int A,int B,int C){
e[idx] = B,a[idx] = C,ne[idx] = h[A],h[A] = idx++;
}
int dijkstra(){
memset(dist,0x3f,sizeof dist);
dist[1][0] = 0;
priority_queue<PII,vector<PII>,greater<PII>> heap;
heap.push({0,1});
while(!heap.empty()){
PII t = heap.top();
heap.pop();
int ver = t.second,d = t.first;
if(st[ver][d % k]) continue;
st[ver][d % k] = true;
for(int i = h[ver];i != -1;i = ne[i]){
int j = e[i],w = a[i];
int tmp = d;
if(d < w) tmp += ceil(w - d,k) * k;
if(dist[j][(tmp + 1) % k] > tmp + 1){
dist[j][(tmp + 1) % k] = tmp + 1;
heap.push({tmp + 1,j});
}
}
}
if(dist[n][0] == INF) return -1;
else return dist[n][0];
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
memset(h,-1,sizeof h);
cin >> n >> m >> k;
for(int i = 1,u,v,w;i <= m;i++){
cin >> u >> v >> w;
add(u,v,w);
}
cout << dijkstra();
return 0;
}