计蒜客ACM Shenyang 2015——M——meeting(dijkstra最短路)

题目大意:两头牛在图的1和n处,现给定一些区域集合Ei,这些区域集合中的点是可以互相到达的,且时间花费都为Ti,问两头牛能否相遇,相遇的最短时间和相遇的点的标记。

题解报告:当初想到跑两边dijkstra,然而脑子抽不知道怎么保存和输出相遇的点的路径,结果就全盘否定,最后也没写多少。。。。。还是做题做少了。。。

思路:这题就是dijkstra最短路,不过建边时候要考虑一个问题,这个题的点为1e5个,那么用邻接表,边会达到1e10个,最短路会超时,所以这时候我们将一个集合加为一个点,点的编号从n+1开始,再将集合中所有的点与这个大点建边,权值为时间Ti,反向建边时权值为0(为什么为0自己画个图就知道了)。这样我们新加了1e5个点,而又因为Si的和不超过1e6,所以我们最后边的总数最大为2e6,这样就不会超时了,也可以开的下数组。开数组大小等细节详细看代码吧~

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
#include <cmath>
using namespace std;

/*
    dijkstra*2,枚举最短路的每个节点
    注意建边的技巧,这题n为1e5,不能直接建边,否则超时
    将每个s后的s个边与一个源点建立s条边,权值为t表示时间
    反向建边时权值为0
    这样总边数为2*1e6
    这有着网络流的建边思想
*/

typedef long long ll;

const ll INF=0x3f3f3f3f;

const int maxn=1e5+10;//点
const int maxm=2e6+10;//边

struct Edge
{
    int from;
    int to;
    int next;
    ll dist;
}edges[maxm];

struct HeapNode
{
    ll d;
    int u;
    HeapNode(ll _d,int _u):d(_d),u(_u){}
    bool operator < (const HeapNode &rhs)const
    {
        return d>rhs.d;
    }
};

int head[maxn+maxm],tot;//节点数多增加1e6个

int n,m;

int vis[maxn+maxm];

ll dist_x[maxn+maxm],dist_y[maxn+maxm];

void init()
{
    memset(head,-1,sizeof(head));
    tot=0;
}

void add_edges(int u,int v,ll dist)
{
    edges[tot].from=u;
    edges[tot].to=v;
    edges[tot].dist=dist;
    edges[tot].next=head[u];
    head[u]=tot++;
}

void dijkstra(int s,ll *d)//求点s到每一个点的最短距离,存入d数组中
{
    priority_queue<HeapNode>Q;
    for(int i=0;i<=n+m+1;i++)d[i]=INF;
    d[s]=0;
    memset(vis,0,sizeof(vis));
    //memset(visNode,0,sizeof(visNode));
    Q.push(HeapNode(0,s));
    while(!Q.empty())
    {
        HeapNode N=Q.top();Q.pop();
        int u=N.u;
        if(vis[u])continue;
        vis[u]=true;
        for(int i=head[u];i!=-1;i=edges[i].next)
        {
            int v=edges[i].to;
            if(d[v]>d[u]+edges[i].dist)
            {
                d[v]=d[u]+edges[i].dist;
                Q.push(HeapNode(d[v],v));
            }
        }
    }
}


int main()
{
    int T;
    scanf("%d",&T);
    int Case=1;
    while(T--)
    {
        scanf("%d%d",&n,&m);
        init();
        ll time;
        int si;
        for(int i=1;i<=m;i++)
        {
            scanf("%lld%d",&time,&si);
            int index=n+i;//多增节点从n+1开始编号
            for(int j=1;j<=si;j++)
            {
                int num;
                scanf("%d",&num);
                add_edges(num,index,time);
                add_edges(index,num,0);//为什么是0呢?这样保证连接同一个s的距离只有T;
            }
        }
        dijkstra(1,dist_x);
        dijkstra(n,dist_y);
        ll ans=INF;
        for(int i=1;i<=n;i++)
        {
            ans=min(ans,max(dist_x[i],dist_y[i]));//因为可以等待,所以取两者到每一个点的最大值
        }
        if(ans==INF)
        {
            printf("Case #%d: Evil John\n",Case++);
        }
        else
        {
            printf("Case #%d: %lld\n",Case++,ans);
            bool flag=false;
            for(int i=1;i<=n;i++)
            {
                if(ans==max(dist_x[i],dist_y[i]))
                {
                    if(flag)printf(" ");
                    printf("%d",i);
                    flag=true;
                }
            }
            printf("\n");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Q755100802/article/details/82470063
今日推荐