bzoj4489 [Jsoi2015]地铁线路 最短路

时间:2019-09-18
本文章向大家介绍bzoj4489 [Jsoi2015]地铁线路 最短路,主要包括bzoj4489 [Jsoi2015]地铁线路 最短路使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题目传送门

https://lydsy.com/JudgeOnline/problem.php?id=4489

题解

感觉又被骗了。看这道题的 AC 人数不多,以为是一道很好的题目。结果发现是一个非常一般的最短路啊。

第一问的话,相当于同一个集合内的点可以瞬移,不需要花钱。于是可以每条线路建一个点,把每个站点向所在线路连边,边权为 \(0\);每条道路向站点连边,边权为 \(1\)。显然从 \(S\)\(T\) 的最短路就是第一问的答案。最短路可以通过 01bfs 实现。

然后第二问的话,也可以继续建图来做。但是有一个更方便的做法。我们可以通过第一问得到的最短路给每一条线路和每个站点分层。然后对于同一层,枚举每一条线路,用这条线路上低一层的点来更新本层的点。(更新可以通过前后缀最大值来实现)


代码如下。

#include<bits/stdc++.h>
#include<tr1/unordered_map>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back

template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}

typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;

template<typename I>
inline void read(I &x) {
    int f = 0, c;
    while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    x = c & 15;
    while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    f ? x = -x : 0;
}

const int N = 3e5 + 50000 + 7;
const int M = 3e5 + 7;
const int INF = 0x3f3f3f3f;

int n, m, nod, S, T, hd, tl;
int dis[N], p[N], mxt[N], mxt2[N], pre[N], suf[N];
std::deque<int> q;
std::tr1::unordered_map<std::string, int> mp;
std::vector<int> v[N];
char tmp[50];

struct Edge { int to, ne; } g[N * 6]; int head[N], tot;
inline void addedge(int x, int y) { g[++tot].to = y, g[tot].ne = head[x], head[x] = tot; }
inline void adde(int x, int y) { addedge(x, y), addedge(y, x); }

inline void build() {
    for (int i = 1; i <= n; ++i) {
        int len = v[i].size();
        for (int j = 0; j < len; ++j) adde(i + m, v[i][j]);
    }
}

inline void bfs() {
    q.push_back(S);
    memset(dis, -1, sizeof(dis)), dis[S] = 0;
    while (!q.empty()) {
        int x = q.front(); q.pop_front();
        if (x <= m) {
            for fec(i, x, y) if (!~dis[y]) dis[y] = dis[x] + 1, q.push_back(y);
        } else for fec(i, x, y) if (!~dis[y]) dis[y] = dis[x], q.push_front(y);
    }
}

inline bool cmp(const int &x, const int &y) { return dis[x + m] < dis[y + m]; }
inline void work() {
    build();
    bfs();
    for (int i = 1; i <= n; ++i) p[i] = i;
    std::sort(p + 1, p + n + 1, cmp);
    int r = 0;
    while (r < n && dis[p[r + 1] + m] <= 0) ++r;
    for (int i = 1; i <= n; ++i) {
        int l = r + 1;
        while (r < n && dis[p[r + 1] + m] == i) ++r;
        for (int j = l; j <= r; ++j) {
            int id = p[j], len = v[id].size();
            pre[0] = suf[len + 1] = -INF;
            for (int k = 0; k < len; ++k) pre[k + 1] = std::max(pre[k] + 1, dis[v[id][k]] == i - 1 ? mxt[v[id][k]] : -INF);
            for (int k = len - 1; ~k; --k) suf[k + 1] = std::max(suf[k + 2] + 1, dis[v[id][k]] == i - 1 ? mxt[v[id][k]] : -INF);
            for (int k = 0; k < len; ++k) if (dis[v[id][k]] == i) smax(mxt[v[id][k]], std::max(pre[k + 1], suf[k + 1]));
        }
    }
    printf("%d\n", dis[T]);
    printf("%d\n", mxt[T]);
}

inline void init() {
    read(n), read(m);
    for (int i = 1; i <= m; ++i) scanf("%s", tmp), mp[tmp] = i;
    for (int i = 1; i <= n; ++i) {
        int l;
        read(l);
        while (l--) scanf("%s", tmp), v[i].pb(mp[tmp]);
    }
    scanf("%s", tmp), S = mp[tmp];
    scanf("%s", tmp), T = mp[tmp];
}

int main() {
#ifdef hzhkk
    freopen("hkk.in", "r", stdin);
#endif
    init();
    work();
    fclose(stdin), fclose(stdout);
    return 0;
}

原文地址:https://www.cnblogs.com/hankeke/p/bzoj4489.html