#include using namespace std; typedef pair PII; const int INF = 0x3f3f3f3f; const int N = 2e6 + 5, M = N << 1; // 1e4的顶点 * 1e2的分层 // first:起点距离目标点的权重i/ / second:目标点编号 int dis[N]; // 判断是否以某个顶点作为出发点进行松弛 bool st[N]; // m条边 // k个的整数倍 int n, m, k; // 链式前向星 int e[M], h[N], idx, w[M], ne[M]; void add(int a, int b, int c = 0) { e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++; } // 最短路搜索 void dijkstra(int s) { // 优先队列 priority_queue q; // n个顶点 memset(dis, INF, sizeof dis); // 起点距离自己为0 dis[s] = 0; q.push({0, s}); while (q.size()) { int u = q.top().second; q.pop(); // 该点已经被作为起点出发了 if (st[u]) continue; // 标记此点已经被作为起点使用过 st[u] = 1; for (int i = h[u]; ~i; i = ne[i]) { int v = e[i]; // 获取当前顶点的目标点 int t = dis[u] + 1; // 到达下一个节点的时间 if (t < w[i]) t += ((w[i] - dis[u] + k - 1) / k) * k; // https://www.luogu.com.cn/problem/solution/P9751 // while (t < w[i]) t += k; // w[i]:最早开放时间 // 松弛 if (dis[v] > t) { dis[v] = t; // 保证每次筛选出来的都是离起点最近的点 q.push({-dis[v], v}); } } } } // 计算给定的点在新层中的索引 int get(int layer, int x) { return layer * n + x; } int main() { memset(h, -1, sizeof h); // 初始化链式前向星 cin >> n >> m >> k; // 读入m条边的信息 while (m--) { // a为起始点//b为终点 // c是最早开放时间 int a, b, c; cin >> a >> b >> c; // 存入分层图 // get(i, a) : 当前层点索引 // get((i + 1) % k, b):下一层K步后所能到达的点 // 当前层和第i+1层建图 for (int i = 0; i < k; i++) add(get(i, a), get((i + 1) % k, b), c); } // 调用迪克斯特拉 dijkstra(1); // 没有找到合法路径 if (dis[n] == INF) cout << -1 << endl; else cout << dis[n] << endl; return 0; }