HDU 5521 Meeting (建图技巧+最短路)

版权声明:希望能在自己成长的道路上帮到更多的人,欢迎各位评论交流 https://blog.csdn.net/yiqzq/article/details/82950847

原题地址:http://acm.hdu.edu.cn/showproblem.php?pid=5521

题意:给一些集合,集合里的任意两点可以花费某一时间 t i ti 到达
有两人分别在 1 1 号点和 n n 号点
两人同时出发,问在哪一点见面花费的时间最短
输出最短时间和见面的点(如果有多个点从小到大输出多个)

思路:因为集合太大,不可以把每个集合的所有点建边,我们引入m个虚拟的点,每个集合的点连接引入的点,然后集合的点向虚拟的点建一条正常权值的边,再建一条反向边,权值为0.这样子建边的复杂度从 n 2 n^2 变成了 2 n 2n .
然后只要跑正反两遍dij,然后遍历寻找一个最优的点就行了.

参考博客:https://blog.csdn.net/Code92007/article/details/82795407

#include <bits/stdc++.h>
#define eps 1e-8
#define INF 0x3f3f3f3f3f3f3f3f
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)+1
#define CLR(x,y) memset((x),y,sizeof(x))
#define fuck(x) cerr << #x << "=" << x << endl

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int seed = 131;
const int maxn = 30e5 + 5;
const int mod = 1e9 + 7;
struct node {
    int v, w, nxt;
    node() {}
    node(int v, int w): v(v), w(w) {}
    bool operator <(const node &a)const {
        return w > a.w;
    }
} e[maxn];
int tot, head[maxn];
void add_edge(int u, int v, int  w) {
    e[tot].v = v;
    e[tot].w = w;
    e[tot].nxt = head[u];
    head[u] = tot++;
}
int T, n, m;
int a[maxn];
bool vis[maxn];
ll dis[3][maxn];
int DIS[maxn];
void dij(int start, int id) {
    for (int i = 0; i <= n + m; i++) {
        dis[id][i] = INF;
        vis[i] = 0;
    }
    priority_queue<node>q;
    dis[id][start] = 0;
    q.push(node(start, dis[id][start]));
    while (!q.empty()) {
        int u = q.top().v;
        q.pop();
        if (vis[u]) continue;
        vis[u] = 1;
        for (int i = head[u]; ~i; i = e[i].nxt) {
            int v = e[i].v;
            if (dis[id][v] > dis[id][u] + e[i].w) {
                dis[id][v] = dis[id][u] + e[i].w;
                q.push(node(v, dis[id][v]));
            }
        }
    }
}

int main() {
    scanf("%d", &T);
    for (int cas = 1; cas <= T; cas++) {
        CLR(head, -1);
        tot = 0;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= m; i++) {
            int val, num;
            scanf("%d%d", &val, &num);
            for (int j = 1; j <= num; j++) {
                scanf("%d", &a[j]);
                add_edge(a[j], n +i, val);
                add_edge(n + i, a[j], 0);
            }
        }

        dij(1, 1);
        dij(n, 2);

        ll MIN = INF;
        vector<ll>v;
        v.clear();
        for (int i = 1; i <= n; i++) {
            ll maxx = max(dis[1][i], dis[2][i]);
            if (maxx < MIN) {
                MIN = maxx;
                v.clear();
                v.push_back(i);
            } else if (maxx == MIN) {
                v.push_back(i);
            }
        }
        printf("Case #%d: ", cas);
        if (MIN == INF) printf("Evil John\n");
        else {
            printf("%d\n", MIN);
            int cnt=v.size();
            for (int i = 0; i < cnt; i++) {
                printf("%d%c", v[i], i == cnt - 1 ? '\n' : ' ');

            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yiqzq/article/details/82950847