hdu5521 ( Dijkstra )

题目描述:

给定一张图,问从1和n相遇的最短时间。

这道题的输入比较特殊,不能直接存,所以怎么输入,怎么存取,只要可以访问到一个节点的相邻节点就可以,由于spfa算法的时间复杂度为m*n,而Dijkstra算法的时间复杂度为m*log(n),

其实Dijkstra就是用优先队列替换掉了spfa中的普通队列,每次都是用权值最小的点去更新别人,可以这么理解,用用权值最小的点a去更新其他节点,在更新节点中必然会有一个节点已经是

最短路,假设是b,因为源点到其他节点的距离+其他节点到b节点的距离 >  dist[a] + edge[a][b], 因为 源点到其他节点的距离 > dist[a] + edge[a][b];最多有10^6个点,那么可能就会有 10^12条边 ,时间复杂度为 10^12 * log(10^5) = 15*10^12;所以主要取决于有多少条边,分析一下如果一个节点已经更新了它所在集合中的其他点,那么这个集合中所有点之间的边就不会在更新了,假设a,b,c,d,e在一个集合里,集合之间的路径为edge,假设a是更新点,说明b,c,d,e的最短路大于a的最短路, 说明b,c,d的最短路一定是由a得到,而不是 b,c,d,Dis[a]+edge < Dist[k] +edge,k属于b,c,d。所以集合只会被访问一次。

//有可能一个人在家等他
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#include <math.h>
#define  maxn 1100000
#define  LL    long long
using namespace std;
int t;
int n,m;
vector < int >  G[maxn];
int tt[maxn],ss[maxn];
vector < int >  Set[maxn];
LL Dist[3][maxn];
int vis[maxn];
int VISIT[maxn];
 LL answer[maxn];
 LL ans[maxn];
struct node
{
    int u,dist;
    friend bool operator < (node a,node b)
    {
        return a.dist>b.dist;
    }
};
void init()
{
    memset(vis,0,sizeof(vis));
    memset(VISIT,0,sizeof(VISIT));
}

void Dijkstra(int start)
{
    int kind;
    if(start==1)
        kind=1;
    else
        kind=2;
    priority_queue < node >    que;
    node s;
    s.u=start;
    s.dist=0;
    Dist[kind][start]=0;
    que.push(s);
    while(!que.empty())
    {
       s=que.top();
       que.pop();
       if(vis[s.u]==1)
        continue;
       vis[s.u]=1;
       int from=s.u;
       for(int i=0;i<Set[from].size();i++)  //找到所在集合
       {
          int j=Set[from][i]; //j代表哪个集合
          if(VISIT[j]==1)
            continue;
          VISIT[j]=1;
          int edge= tt[j]; //edge代表长度
          for(int k=0;k<G[j].size();k++)  //遍历相邻节点
           {
              node Next;
              int to=G[j][k];
              if(Dist[kind][to]>Dist[kind][from]+edge  || Dist[kind][to]==-1 )
              {
                 Dist[kind][to]=Dist[kind][from] + edge;
                 Next.dist=Dist[kind][to];
                 Next.u=to;
                 que.push(Next);
              }
           }
       }
    }
}

void solve()
{
    init();
    Dijkstra(1);
    init();
    Dijkstra(n);
    for(int i=1;i<=n;i++)
    {
       // cout<<Dist[1][i]<<" "<<Dist[2][i]<<endl;
        if(Dist[1][i]==-1 || Dist[2][i]==-1)
            answer[i]=-1;
        else
        answer[i]=max(Dist[1][i],Dist[2][i]);
    }
     LL MIN=-1;
     for(int i=1;i<=n;i++)
     {
         if(MIN > answer[i] || (MIN==-1) )
            MIN=answer[i];
     }
     if(MIN==-1)
        printf("Evil John\n");
     else
     {
          printf("%I64d\n",MIN);
          int flag=0;
          for(int i=1;i<=n;i++)
          {
              if(MIN==answer[i])
              {
                if(flag==1)
                    printf(" ");
                printf("%d",i);
                flag=1;
              }
          }

          printf("\n");
     }
}
void input()
{
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&tt[i],&ss[i]);
            for(int j=1;j<=ss[i];j++)
            {
                int input;
                scanf("%d",&input);
                G[i].push_back(input);
                Set[input].push_back(i);
            }
        }
}
void Init()
{
   for(int i=0;i<maxn;i++)
   {
       G[i].clear(); Set[i].clear();
   }
    memset(Dist,-1,sizeof(Dist));
}
int main()
{
    //freopen("test.txt","r",stdin);
    scanf("%d",&t);
    int Case=0;
   // printf("%d\n",inf);
   // cout<<inf<<endl;
    while(t--)
    {
        Init();
        input();
        printf("Case #%d: ",++Case);
        solve();
    }
    return 0;
}

 

posted on 2015-11-20 19:31  爱装逼的书呆子  阅读(664)  评论(0编辑  收藏  举报

导航