学习最短路建图 HUD 5521

http://acm.hdu.edu.cn/showproblem.php?pid=5521

题目大意:有n个点,m个集合,每个集合里面的点都两两可达且每条边权值都是val,有两个人A, B,A在pos=1,B在pos=n,问两者相遇的最短时间,输出相遇地点,如果有多个最短时间,输出的相遇地点按从小到大排序。

思路:因为集合暴力枚举点肯定mle。所以我不会TAT(我好菜啊)。于是看了一下别人的想法, 就是新建一个节点,然后让集合里面的所有节点都连向他, 然后权值定为和原来的权值一样,也是val(但是最后的ans要除以2)。 TAT,既然我都已经刷过网络流了,既然这个都没有想到

接下来就简单了。。。dijstra跑两次就好了= =

//看看会不会爆int!数组会不会少了一维!
//取物问题一定要小心先手胜利的条件
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define haha printf("haha
")
const LL inf = 1e17;
const int maxn = 2e6 + 5;
struct Edge{
    int from, to; LL val;
    Edge(int f = 0, int t = 0, LL val = 0): from(f), to(t), val(val){}
};
struct Point{
    int from; LL val;
    Point(int f = 0, LL val = 0): from(f), val(val){}
    bool operator < (const Point &a) const{
        return val > a.val;
    }
};
vector<Edge> G[maxn];
int kase, n, m;
int a[maxn];

void build(int newpoint, int cnt, LL t){
    for (int i = 1; i <= cnt; i++){
        G[a[i]].push_back(Edge(a[i], newpoint, t));
        G[newpoint].push_back(Edge(newpoint, a[i], t));
    }
}
LL d[maxn], d1[maxn], d2[maxn];
void dijstra(int s){
    for (int i = 1; i <= n + m; i++){
        d[i] = inf;
    }
    d[s] = 0;
    priority_queue<Point> que;
    que.push(Point(s, d[s]));
    while (!que.empty()){
        Point u = que.top(); que.pop();
        int len = G[u.from].size();
        for (int i = 0; i < len; i++){
            Edge p = G[u.from][i];
            int v = p.to;
            if (d[v] > d[u.from] + p.val){
                d[v] = d[u.from] + p.val;
                que.push(Point(v, d[v]));
            }
        }
    }
}

void solve(){
    dijstra(1);
    for (int i = 1; i <= n; i++) d1[i] = d[i];
    dijstra(n);
    for (int i = 1; i <= n; i++) d2[i] = d[i];
    LL minival = inf;
    for (int i = 1; i <= n; i++){
        minival = min(minival, max(d1[i], d2[i]));
    }
    if (minival == inf) {
        printf("Case #%d: Evil John
", ++kase);
        return ;
    }
    vector<int> v;
    for (int i = 1; i <= n; i++){
        if (minival == max(d1[i], d2[i])) v.push_back(i);
    }
    printf("Case #%d: %I64d
", ++kase, minival / 2);
    for (int i = 0; i < v.size(); i++){
        printf("%d%c", v[i], i == v.size() - 1 ? '
' : ' ');
    }
}

int main(){
    int T; cin >> T;
    while (T--){
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n + m; i++) G[i].clear();
        for (int i = 1; i <= m; i++){
            LL t; int cnt; scanf("%I64d%d", &t, &cnt);
            for (int j = 1; j <= cnt; j++){
                scanf("%d", a + j);
            }
            build(i + n, cnt, t);
        }
        solve();
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/heimao5027/p/5960234.html