[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;
}
posted @ 2024-04-11 09:15  Time_Limit_Exceeded  阅读(178)  评论(0编辑  收藏  举报