luogu P4568 [JLOI2011]飞行路线

题目链接:luogu P4568 [JLOI2011]飞行路线

题目大意:

题解:
建立多层图,最多免费\(k\)次,所以有\(k+1\)层图,第\(i\)层表示当前已用\(i\)次免费机会,加边时在各层的都加上同一条边,一次免费相当于在上下两层的两点之间建立一条权值为\(0\)的边,起点在第\(0\)层,对整个多层图跑一遍最短路,一个点的最短距离就是其在各层中的最短距离的最小值。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
#define io_speed_up ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define INF 0x3f3f3f3f

int head[110010], n, m, k, s, t, cnt;
long long dis[110010];
bool vis[110010];

struct Node {
    int u;
    long long dis;
    bool operator<(const Node &x) const { return dis > x.dis; }
};

struct Edge {
    int v, next;
    long long w;
} edge[11000010];

void addEdge(int u, int v, long long w) {
    edge[++cnt].v = v;
    edge[cnt].w = w;
    edge[cnt].next = head[u];
    head[u] = cnt;
}

void dijkstra(int s) {
    priority_queue<Node> q;
    for (int i = 0; i <= (k + 1) * n - 1; ++i) dis[i] = INF;
    dis[s] = 0;
    q.push(Node{s, 0});
    while (!q.empty()) {
        int u = q.top().u;
        long long l = q.top().dis;
        q.pop();
        if (l > dis[u]) continue;
        for (int i = head[u]; i; i = edge[i].next) {
            int v = edge[i].v;
            long long len = edge[i].w;
            if (dis[v] > dis[u] + len) {
                dis[v] = dis[u] + len;
                q.push(Node{v, dis[v]});
            }
        }
    }
}

int main() {
    io_speed_up;
    cin >> n >> m >> k >> s >> t;
    for (int i = 1, u, v, w; i <= m; ++i) {
        cin >> u >> v >> w;
        for (int j = 0; j <= k; ++j) {
            int tu = u + n * j, tv = v + n * j;
            if (j != k) {
                addEdge(tu, tv + n, 0);
                addEdge(tv, tu + n, 0);
            }
            addEdge(tu, tv, w);
            addEdge(tv, tu, w);
        }
    }
    dijkstra(s);
    long long ans = INF;
    for (int i = 0; i <= k; ++i) {
        ans = min(ans, dis[t + n * i]);
    }
    cout << ans;
    return 0;
}
posted @ 2022-01-30 20:16  ZZHHOOUU  阅读(22)  评论(0编辑  收藏  举报