HDU 5521 Meeting 最短路

题意:

\(n\)个点和\(m\)个点的集合\(E_i\),每个集合中的点两两相邻而且通过任意两点之间需要的时间为\(t_i\)
有两个人分别从\(1\)\(n\)出发,确定一个相遇点使得两个人相遇的时间最短。

参考博客

分析:

起初想法是跑两遍最短路,分别计算\(1\)\(n\)为起点时的最短路\(ds(i)\)\(dt(i)\)
那么所求的最短时间为\(min\\\{ max(ds(i), dt(i)) \\\}\)

但是边的数量太多了,传统的建图方法行不通。
考虑题目所给的条件,在途中新增\(m\)个点代表这些集合。
对于一个点\(u\)和它所属的集合\(S\),建一条\(u \rightarrow S\)权值为\(0\)的边,和一条\(S \rightarrow u\)的权值为\(w\)的边。
然后求最短路就是答案。

说一下我对这种见图方法的理解:

  • \(u \rightarrow S\)表示从点\(u\)进入集合,因为点本来就在集合中所以不需要花费。
  • \(S \rightarrow u\)表示在集合中从一个点移动到另一个点,花费为\(w\)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#define MP make_pair
using namespace std;

typedef pair<int, int> PII;
const int maxn = 200000 + 10;
const int INF = 0x3f3f3f3f;

struct Edge
{
    int u, v, d;
    Edge() {}
    Edge(int u, int v, int d):u(u), v(v), d(d) {}
};

int n, m;
vector<int> G[maxn];
vector<Edge> edges;

void init(int n) {
    for(int i = 1; i <= n; i++) G[i].clear();
    edges.clear();
}

void AddEdge(int u, int v, int d) {
    edges.push_back(Edge(u, v, d));
    edges.push_back(Edge(v, u, 0));
    int m = edges.size();
    G[u].push_back(m - 2);
    G[v].push_back(m - 1);
}

int ds[maxn], dt[maxn];
bool vis[maxn];

void Dijkstra(int* d, int s) {
    memset(d, 0x3f, sizeof(ds));
    memset(vis, false, sizeof(vis));
    d[s] = 0;
    priority_queue<PII, vector<PII>, greater<PII> > Q;
    Q.push(MP(0, s));

    while(!Q.empty()) {
        PII x = Q.top(); Q.pop();
        int u = x.second;
        if(vis[u]) continue;
        vis[u] = true;
        for(int i = 0; i < G[u].size(); i++) {
            Edge& e = edges[G[u][i]];
            int v = e.v;
            if(d[u] + e.d < d[v]) {
                d[v] = d[u] + e.d;
                Q.push(MP(d[v], v));
            }
        }
    }
}

int main()
{
    int T; scanf("%d", &T);
    for(int kase = 1; kase <= T; kase++) {
        scanf("%d%d", &n, &m);
        init(n + m);
        for(int i = 1; i <= m; i++) {
            int d, cnt; scanf("%d%d", &d, &cnt);
            while(cnt--) {
                int u; scanf("%d", &u);
                AddEdge(n + i, u, d);
            }
        }

        printf("Case #%d: ", kase);

        Dijkstra(ds, 1);
        if(ds[n] == INF) { printf("Evil John\n"); continue; }
        Dijkstra(dt, n);

        #ifdef DEBUG
        printf("ds: ");
        for(int i = 1; i <= n; i++) printf("%d ", ds[i]);
        printf("\ndt: ");
        for(int i = 1; i <= n; i++) printf("%d ", dt[i]);
        printf("\n");
        #endif

        int ans = INF;
        for(int i = 1; i <= n; i++) ans = min(ans, max(ds[i], dt[i]));
        printf("%d\n", ans);

        bool flag = false;
        for(int i = 1; i <= n; i++) {
            if(max(ds[i], dt[i]) == ans) {
                if(flag) printf(" ");
                printf("%d", i); flag = true;
            }
        }
        printf("\n");
    }

    return 0;
}

你可能感兴趣的:(HDU 5521 Meeting 最短路)