HDU5521 Meeting 题解 最短路

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5521

题目大意:
\(n\) 个点 \(m\) 个集合,一个点可能处于若干个集合内,属于第 \(i\) 个集合的任意两点间的距离是 \(t_i\) ,点 \(1\) 是起点,点 \(n\) 是终点。
你现在需要找到所有点中到 \(1\)\(n\) 两点的距离的较大值的最小值,并输出所有满足要求的点。

解题思路:
这道题目难的不是最短路,而是建图。
因为最多可能有 \(n\) 个点在同一个集合,而 \(n \le 2 \times 10^5\) ,所以两两之间建边显然是不可取的,所以我们需要采用另一种方式建图:
为每一个集合对应一个点,第 \(i\) 个集合对应点 \(n+i\) ,然后从 \(n+i\) 连向所有第 \(i\) 个集合中的点一条权值为 \(t_i\) 的有向边,从第 \(i\) 个集合中的所有点连向点 \(n+i\) 一条权值为 \(0\) 的边。然后分别以点 \(1\) 和点 \(n\) 为起点求两边最短路。

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 200020;
int T, n, m, e, dist1[maxn], dist2[maxn];
bool inq[maxn];
struct Node {
    int v, w;
    Node () {};
    Node (int _v, int _w) { v = _v; w = _w; }
};
vector<Node> g[maxn];
queue<int> que;
vector<int> ans_vec;
// 一共n+m个点
void init() {
    for (int i = 1; i <= n+m; i ++) g[i].clear();
}
void spfa(int st, int dist[]) {
    memset(dist, -1, sizeof(int)*(1+n+m));
    memset(inq, 0, sizeof(inq));
    while (!que.empty()) que.pop();
    dist[st] = 0;
    que.push(st);
    while (!que.empty()) {
        int u = que.front();
        que.pop();
        inq[u] = false;
        int sz = g[u].size();
        for (int i = 0; i < sz; i ++) {
            int v = g[u][i].v, w = g[u][i].w;
            if (dist[v] == -1 || dist[v] > dist[u] + w) {
                dist[v] = dist[u] + w;
                if (!inq[v]) {
                    inq[v] = true;
                    que.push(v);
                }
            }
        }
    }
}
int main() {
    scanf("%d", &T);
    for (int cas = 1; cas <= T; cas ++) {
        scanf("%d%d", &n, &m);
        init();
        for (int i = 1; i <= m; i ++) {
            int t, s, u;
            scanf("%d%d", &t, &s);
            while (s --) {
                scanf("%d", &u);
                g[n+i].push_back(Node(u, t));
                g[u].push_back(Node(n+i, 0));
            }
        }
        spfa(1, dist1);
        spfa(n, dist2);
        int ans = -1;
        for (int i = 1; i <= n; i ++)
            if (dist1[i] != -1 && dist2[i] != -1 && (ans==-1 || ans > max(dist1[i], dist2[i])))
                ans = max(dist1[i], dist2[i]);
        printf("Case #%d: ", cas);
        if (ans == -1) puts("Evil John");
        else {
            printf("%d\n", ans);
            ans_vec.clear();
            for (int i = 1; i <= n; i ++) if (dist1[i] != -1 && dist2[i] != -1 && max(dist1[i], dist2[i])==ans)
                ans_vec.push_back(i);
            int sz = ans_vec.size();
            for (int i = 0; i < sz; i ++) {
                if (i) putchar(' ');
                printf("%d", ans_vec[i]);
            }
            puts("");
        }
    }
    return 0;
}

posted @ 2019-12-07 21:16  quanjun  阅读(140)  评论(0编辑  收藏  举报