HDU 5521 Meeting(虚点建图)

127 篇文章 0 订阅
85 篇文章 2 订阅

Meeting

题意:从 1 1 1 n n n m m m处具有 s s s个点的点集合,每个集合任意两点的距离为 t t t,问两人同时分别从 1 1 1 n n n出发,要相遇的最短的距离是多少并输出相遇点,如果有多个答案按升序输出。

题解:真是又涨知识了…对于每个集合增加一个虚点,集合里的每个点向这个虚点建一条距离为 t / 2 t/2 t/2的边,这样就保持了原集合任意两点的距离不变。然后以 1 1 1为源点跑一次最短路,以 n n n为源点跑一次最短路,然后枚举这 i i i个点集合即可。不过由于可能会有精度问题,所以可以先向虚点建边的时候边权设置为 t t t,最后再除以 2 2 2

代码

#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const LL inf = 1e18, N = 200100;
int n,m;
bool vis[N];
LL dis[N][2];

struct qnode{
    int v;
    LL c;
    qnode(int x,LL y) : v(x), c(y){}
    bool operator < (const qnode & u)const{
        return c > u.c;
    }
};

struct Edge{
    int v; LL cost;
    Edge(int _v = 0, LL _cost = 0) : v(_v), cost(_cost) {}
};
vector<Edge> E[N];

void dijkstra(int s,int f){
    memset(vis,0,sizeof vis);
    for(int i = 1; i < N; ++i) dis[i][f] = inf;
    priority_queue<qnode> pq;
    dis[s][f] = 0;
    pq.push(qnode(s,0));
    while(!pq.empty()) {
        qnode t = pq.top();
        pq.pop();
        int u = t.v;
        if(vis[u]) continue;
        vis[u] = 1;
        for(int i = 0; i < E[u].size(); ++i){
            int v = E[u][i].v;
            LL cost = E[u][i].cost;
            if(!vis[v] && dis[v][f] > dis[u][f] + cost) {
                dis[v][f] = dis[u][f] + cost;
                pq.push(qnode(v,dis[v][f]));
            }
        }
    }
}

void addEdge(int u,int v,int w) {
    E[u].push_back(Edge(v,w));
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.in","r",stdin);
#endif
    int T, s, t, u, more, w = 0;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i = 0; i < N; ++i)
            E[i].clear();
        more = n;
        for(int i = 0; i < m; ++i){
            scanf("%d%d",&t,&s);
            more++;
            while(s--){
                scanf("%d",&u);
                addEdge(u,more,t);
                addEdge(more,u,t);
            }
        }
        dijkstra(1,0);
        dijkstra(n,1);
        LL ans = inf;
        for(int i = 1; i <= n; ++i){
            ans = min(ans,max(dis[i][0], dis[i][1]));
        }
        printf("Case #%d: ",++w);
        if(ans == inf) puts("Evil John");
        else{
            printf("%lld\n",ans / 2);
            vector<int> v;
            for(int i = 1; i <= n; ++i){
                if(ans == max(dis[i][0], dis[i][1]))
                    v.push_back(i);
            }
            for(int i = 0; i < v.size(); ++i)
                printf("%d%c",v[i],i == v.size() - 1 ? '\n' : ' ');
        }
    }
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值