Preface

第三次做这题了...

顺便当成博客迁移了。下面的题解是高二上的时候写的,在 Hexo 的 blog,这里直接进行迁移:https://gyrojeff.moe/2020/09/18/P4568-JLOI2011-%E9%A3%9E%E8%A1%8C%E8%B7%AF%E7%BA%BF-%E5%88%86%E5%B1%82%E5%9B%BE%E6%9C%80%E7%9F%AD%E8%B7%AF/

题面

https://www.luogu.com.cn/problem/P4568

题解

由于可以有$k$次免费,这里构建分层图:

  • 有$k+1$层完全一样的图
  • 每条边在层与层之间单向连接,但是费用为0

那么这样构建的图的第$i$层的$t$点就是免费了$i - 1$次的最小费用。

方程:
$$
\text {ans} = \min _ {0 \leq i \leq k} \text {dis} [t_i]
$$

常见问题

  • 如何防止从下面的层去上面?单向
  • 如何建图?思考一下OpenCV当中的图像,其实他们的内存地址是连续的,所以我们可以把他们放在一个一维数组当中,只不过开了$n\times k$个点罢了。

图片(Ref @SuperJvRuo)

代码

#include <iostream>
#include <queue>
#include <cstring>
#define int long long

using namespace std;

const int maxn = 1e4+5;
const int maxm = 5e4+5;
const int maxk = 15;

struct edge { int next, to, w; } g[(maxm * maxk) << 2];
int head[maxn * maxk], dis[maxn * maxk], vis[maxn * maxk], ecnt = 2, n, m, k, s, t;

void _add_edge(int u, int v, int w) {
    g[ecnt] = edge { head[u], v, w };
    head[u] = ecnt ++;
}

void add_edge(int u, int v, int w) {
    _add_edge(u, v, w);
    _add_edge(v, u, w);
}

void add_edge(int u, int v, int k, int w) {
    add_edge(k * n + u, k * n + v, w);
}

void add_edge(int u, int v, int k1, int k2, int w) {
    _add_edge(k1 * n + u, k2 * n + v, w);
    _add_edge(k1 * n + v, k2 * n + u, w);
}

struct node {
    int pos, dis;

    friend bool operator < (const node &a, const node &b) {
        return a.dis > b.dis;
    }
};

priority_queue<node> q;

void dijkstra() {
    memset(dis, 0x7f, sizeof(dis));
    dis[s] = 0;
    q.push(node { s, 0 });
    while (!q.empty()) {
        int u = q.top().pos; q.pop();
        if (vis[u]) continue;
        vis[u] = 1;
        for (int e = head[u]; e; e = g[e].next) {
            int v = g[e].to;
            if (vis[v]) continue;
            if (dis[v] > dis[u] + g[e].w) {
                dis[v] = dis[u] + g[e].w;
                q.push(node { v, dis[v] });
            }
        }
    }
}

signed main() {
    cin >> n >> m >> k >> s >> t;
    while (m --> 0) {
        int u, v, w; cin >> u >> v >> w;
        for (int i = 0; i <= k; i ++)
            add_edge(u, v, i, w);
        for (int i = 0; i < k; i ++)
            add_edge(u, v, i, i + 1, 0);
    }
    dijkstra();
    int ans = 8e18;
    for (int i = 0; i <= k; i ++)
        ans = min(ans, dis[t + i * n]);
    cout << ans << endl;
    return 0;
}
最后修改:2022 年 04 月 04 日 11 : 11 PM
真的不买杯奶茶嘛....qwq