[CSP-J 2023] 旅游巴士
[CSP-J 2023] 旅游巴士
知识点:最短路,分层图
注意到小Z是不会在任何地点停留的,包括起点和终点。所以情况只能是,小Z在某个时间点到达起点后,一口气走到终点并上车。
所以难点在于,我们不仅要找到什么时候进入地图,还要找刚好是 \(k\) 的倍数长度的路径。
注意到 \(k\) 很小,而我们只需要考虑是否整除 \(k\) 即可。所以我们可以记录下除以 \(k\) 的余数即可。
于是对于每个点,我们都有 \(k\) 种刚到达该点的状态,记 \(dis[i][u]\) 表示到达 \(u\) 点时,距离 \(mod \ k\) 为 \(i\) 的最短路。
于是我们有以下转移:
设当前在 \(u\) 点,要往 \(v\) 点走,边限制为 \(w\) 则有
\(dis[i][u] < w\) 时, \(dis[(i+1)\%k][v] = dis[i][u]+\lceil \cfrac{w - dis[i][u]}{k} \rceil \cdot k\)
\(dis[i][u] \ge w\) 时,\(dis[(i+1)\%k][v] = dis[i][u]+1\)
由于不能在任意点停留,所以如果当前边通过不了的话,我们只能延迟 \(\lceil \cfrac{w - dis[i][u]}{k} \rceil \cdot k\) 进入景区起点。
很显然,最后的答案就是 \(dis[0][n]\)
#include <bits/stdc++.h>
#define endl '\n'
#define ls u << 1
#define rs u << 1 | 1
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int INF = 0x3f3f3f3f, N = 1e5 + 10;
const int MOD = 1e9 + 7;
const double eps = 1e-6;
const double PI = acos(-1);
inline int lowbit(int x) {return x & (-x);}
struct node {
int t, d, idx;
bool operator > (const node &A) const {
return d > A.d;
}
};
inline void solve() {
int n, m, k; cin >> n >> m >> k;
vector<PII> g[n + 1];
while (m -- ) {
int u, v, w; cin >> u >> v >> w;
g[u].emplace_back(v, w);
}
vector<vector<int>> dis(k, vector<int>(n + 1, INF));
vector<vector<bool>> st(k, vector<bool>(n + 1, false));
priority_queue<node, vector<node>, greater<>> q;
dis[0][1] = 0;
q.push({0, dis[0][1], 1});
while (!q.empty()) {
auto t = q.top(); q.pop();
int u = t.idx;
if (st[t.t][u]) continue;
st[t.t][u] = true;
for (auto ite : g[u]) {
int v = ite.first, w = ite.second;
int val = dis[t.t][u];
if (val < w) val += (w - val + k - 1) / k * k;
int nxt = (t.t + 1) % k;
if (dis[nxt][v] > val + 1) {
dis[nxt][v] = val + 1;
q.push({nxt, dis[nxt][v], v});
}
}
}
if (dis[0][n] == INF) cout << -1 << endl;
else cout << dis[0][n] << endl;
}
signed main() {
#ifdef DEBUG
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
auto now = clock();
#endif
ios::sync_with_stdio(false), cin.tie(nullptr);
cout << fixed << setprecision(2);
int _ = 1;
// cin >> _;
while (_ -- )
solve();
#ifdef DEBUG
cout << "============================" << endl;
cout << "Program run for " << (clock() - now) / (double)CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif
return 0;
}