2015 沈阳站 hdu 5521 Meeting(Dij最短路枚举)

题目地址

题目大意:有N个点,两个人,其中一个人住在点1,另一个人住在点n 。有M个点集,集合内的数表示任意两点的距离为dis ,现在问,如果两个人要见面,需要最短距离是多少,有哪几个点能被当成见面点

解题思路:分别对两个点进行最短路,但是不能直接最短路,这里有一个问题是,边太多了 ,其实也不会很多,每个点集只能被松弛一次,因为里面所有的点已经是最短的状态了,存图的时候注意,存一下每个点所关联的集合,以及每个集合包含的边,当需要松弛u点时,先找到与i相关的每个集合,如果该集合已经被更新过了,那就不需要对其进行更新了,若没更新,对集合里的所有点进行松弛更新

#include <bits/stdc++.h>

using namespace std;

const int maxn = 2e5+100;///点的个数
const int maxm = 1e6+100;///边的个数
typedef long long ll;
const ll INF = 0xfffffff;
int vis[maxn],flag[maxn];///vis表示点是否访问过,flag表示集合是否访问过
ll tt[maxm],dis1[maxn],dis2[maxn];
int n,m;///n个点,m个集合
vector<ll> G[maxn],E[maxm];///G[i]存存在i结点的所有集合,E[i]存结合i里面的所有结点
typedef pair<ll,int> pii;

void Dijkstra(int s,ll *dis)
{
    memset(flag,0,sizeof(flag));
    memset(vis,0,sizeof(vis));
    for(int i = 1 ; i <= n ; i++) ///初始化点的距离
        dis[i] = INF;
    dis[s] = 0;
    priority_queue<pii,vector<pii>,greater<pii> > pq;
    pq.push(make_pair(dis[s],s));
    while(!pq.empty())
    {
        pii tmp = pq.top();
        pq.pop();
        int u = tmp.second; ///队首节点
        if(vis[u])  continue;
        vis[u] = 1;
        for(int i = 0; i < G[u].size(); i++)///对个与队首结点相连的每个结点进行举例更新
        {
            int k = G[u][i];///该结点在第k集合
            if(flag[k]) continue;
            flag[k] = 1;///k集合
            for(int j = 0; j < E[k].size(); j++)
            {
                int v = E[k][j];///对于k集合中的结点v
                if(dis[v] > dis[u]+tt[k])
                {
                    dis[v] = dis[u]+tt[k];
                    pq.push(make_pair(dis[v],v));
                }
            }
        }
     }
}

int main()
{
    int t;
    scanf("%d",&t);
    int cas = 1;
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= n; i++)
            G[i].clear();
        for(int i = 1; i <= m; i++)
        {
            E[i].clear();
            int x,y;///i集合有x个点
            scanf("%lld%d",&tt[i],&x);
            for(int j = 1; j <= x; j++)
            {
                scanf("%d",&y);
                G[y].push_back(i);
                E[i].push_back(y);
            }
        }
        Dijkstra(1,dis1);
        Dijkstra(n,dis2);
        vector<int> v1;
        ll ans = INF;
        for(int i = 1; i <= n; i++)
        {
            ll tmp = max(dis1[i],dis2[i]);
            if(tmp < ans)
            {
                ans = tmp;
                v1.clear();
            }
            if(ans == tmp)
                v1.push_back(i);
        }
        if(ans == INF)
        {
             printf("Case #%d: Evil John\n",cas++);
             continue;
        }
        printf("Case #%d: %lld\n",cas++,ans);
        for(int i = 0; i < v1.size(); i++)
            printf("%d%c",v1[i],i==v1.size()-1 ? '\n' : ' ');
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值