答案是到达状态 `(n, 0)` 的最早时间
从入口出发和从出口离开都必须是 `k` 的倍数。走一条边用时 `1`,所以只记录点号不够,还要记录当前时间对 `k` 的余数。
最终只有余数为 `0` 的出口状态,才是真正能坐上离开巴士的方案。
一节课讲清:不能停留时,如何把“等边开放”变成“改乘更晚的入口巴士”。
从入口出发和从出口离开都必须是 `k` 的倍数。走一条边用时 `1`,所以只记录点号不够,还要记录当前时间对 `k` 的余数。
最终只有余数为 `0` 的出口状态,才是真正能坐上离开巴士的方案。
题目说不能在点上或路上停留,所以“等到边开放”不是合法动作。
但可以选择更晚一班巴士进景区。这样整条已经走过的前缀都会整体后移 `k` 的倍数,仍然没有在景区内等待。
`dist[u][r]` 表示:到达 `u` 号点,且当前时刻模 `k` 等于 `r` 的最早绝对时刻。
每走一条边,时间加 `1`,所以余数从 `r` 变成 `(r + 1) % k`。
这会违反“不想在任何地点或者道路上停留”。代码里不能写成普通等待。
如果当前记录的到达时刻 `t` 还不能走这条边,就把入口出发时间改成更晚一班。这样当前点的到达时刻也增加若干个 `k`。
重点看边 `3 → 4`:它在 `3` 时刻才开放。
| 弹出状态 | 尝试的边 | 开放判断 | 更新结果 |
|---|---|---|---|
| `(1, 0)`,时间 `0` | `1 → 2`,开 `0` | 可以直接走 | `dist[2][1] = 1` |
| `(1, 0)`,时间 `0` | `1 → 3`,开 `0` | 可以直接走 | `dist[3][1] = 1` |
| `(2, 1)`,时间 `1` | `2 → 5`,开 `1` | 可以直接走 | `dist[5][2] = 2`,但余数不是 `0`,不能作为答案 |
| `(3, 1)`,时间 `1` | `3 → 4`,开 `3` | `1` 不够,整体后移到 `4` 再走 | `dist[4][2] = 5` |
| `(4, 2)`,时间 `5` | `4 → 5`,开 `1` | 可以直接走 | `dist[5][0] = 6`,所以最早离开时刻是 `6` |
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = (1LL << 60);
struct Edge {
int to;
int open;
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m, k;
cin >> n >> m >> k;
vector<vector<Edge>> g(n + 1);
for (int i = 1; i <= m; i++) {
int u, v, a;
cin >> u >> v >> a;
g[u].push_back({v, a});
}
vector<vector<ll>> dist(n + 1, vector<ll>(k, INF));
priority_queue<
tuple<ll, int, int>,
vector<tuple<ll, int, int>>,
greater<tuple<ll, int, int>>
> pq;
dist[1][0] = 0;
pq.push({0, 1, 0});
while (!pq.empty()) {
ll tim;
int u, r;
tie(tim, u, r) = pq.top();
pq.pop();
if (tim != dist[u][r]) continue;
for (const Edge &e : g[u]) {
ll depart = tim;
// 不能原地等待;这里表示改乘更晚一班入口巴士,整体后移若干个 k。
if (depart < e.open) {
ll need = e.open - depart;
depart += (need + k - 1) / k * k;
}
ll arrive = depart + 1;
int nr = (r + 1) % k;
if (arrive < dist[e.to][nr]) {
dist[e.to][nr] = arrive;
pq.push({arrive, e.to, nr});
}
}
}
if (dist[n][0] == INF) cout << -1 << '\n';
else cout << dist[n][0] << '\n';
return 0;
}
先把 Dijkstra 的优先队列写熟,再回来看本题的分层状态。
同样把“数字对某个值的余数”当状态,适合迁移本题的建模方式。
练习图论题里“某些点或边要到特定时间后才可用”的思维。