PowerOJ 1799(spfa求最短路+路径输出)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/dl962454/article/details/70212826
  • 西科大新成立了一个WS旅行社。现在在全校范围内招收导游,旅行社为前来应聘的同学设计了一道难题:给应聘者一张地图,看他能否很快的计算出从出发点到达终点的最短路径,这个问题,相信对于来自西科大的你来说,是轻而易举的事情,但是作为旅行社的社长,Bearboy 还要求应聘者能够在地图中画出这条最短路。
  • Input

  • 输入的第一行为一个整数T(T组测试数据<=100)
  • 对于每一组测试数据,第一行为两个整数 N,M。N表示地图上的景点个数(N<=2000)。(1 . 2 . 3....N),M表示道路个数。接下来是M行,每行包括三个整数 S .T .L,表示 景点S与景点T之间的距离是L(L<=1000)
  • 最后一行是两个整数st 和 en ,表示旅行的 起点 和 目的地。
  • Output

  • 对于每组测试数据,输出包括两行,第一行是从st到en的最短路径长度。
  • 第二行是输出从起点到目的地所经过的所有景点(如Sample output所示) 以先后顺序输出,数据保证只有一条最优路径
  • 如果不能到达就输出 none!
  • 每组测试数据后输出一个空行。
  • Sample Input
  • Raw
  • 1
  • 5 8
  • 1 2 1
  • 1 4 10
  • 2 3 5
  • 2 4 1
  • 2 5 12
  • 3 4 1
  • 3 5 1
  • 5 4 8
  • 1 5
  • Sample Output
  • Raw
  • Case 1 : 4
  • 1 2 4 3 5
  • 感谢万能的火山哥。
  • 代码:
  • #include<bits/stdc++.h>
    using  namespace std;
    const  int  maxn=2005;
    const  int  INF=0x7FFFFFFF;//无穷大
    int  pre[maxn];//记录一个前驱
    int  dis[maxn];//记录距离
    int  path[maxn];//记录路径
    bool  vis[maxn];//标记点
    int  head[maxn];//存边
    int  n,m;
    int  tot,cnt;
    /*struct node//两种方法建立邻接表存图
    {
         int v,w,next;
         node(){}
         node(int v,int w,int next):v(v),w(w),next(next){}
    }E[maxn*maxn];
    void add(int u,int v,int w)
    {
         E[tot]=node(v,w,head[u]);
         head[u]=tot++;
    }*/
    struct  node
    {
         int  v,w,next;
    }E[maxn*maxn];
    void  add( int  u, int  v, int  w)
    {
         E[tot].v=v;
         E[tot].w=w;
         E[tot].next=head[u];
         head[u]=tot++;
    }
    void  init()
    {
         tot=0;
         memset (vis, false , sizeof ((vis)));
         memset (head,-1, sizeof (head));
    }
    void  spfa( int  st)
    {
         for ( int i=1;i<=n;i++)
         {
             vis[i]= false ;
             dis[i]=INF;
         }
          queue< int >q;
         q.push(st);
         int now,next;
         dis[st]=0;
         vis[st]= true ;
         pre[st]=-1;
         while (!q.empty())
         {
             now=q.front();
             q.pop();
             vis[now]= false ;//对于弹出队列的就不需要再进入队列了
             for ( int  i=head[now];i!=-1;i=E[i].next)
             {
                 next=E[i].v;
                 if (dis[next]>dis[now]+E[i].w)//类似于三角形两边之和大于第三边,是不是就走距离短的那边了
                 {
                     dis[next]=dis[now]+E[i].w;
                     pre[next]=now;//需要记录一下这个点的前驱,对于输出路径有用
                     if (!vis[next])//如果这点不在队列里面,就把他加如队列然后再找,就这样一直找
                     {
                         vis[next]= true ;
                         q.push(next);
                     }
                 }
             }
         }
    }
    void  print( int  x)//递归输出路径,每次找到当前点的前驱就可以了
    {
         if (pre[x]==-1)  return ;
         print(pre[x]);
         path[++cnt]=x;//放在后面是正着存的,输出就是正着输出的
    }
    int  main()
    {
         int  T;
         scanf ( "%d" ,&T);
         for ( int  cas=1;cas<=T;cas++)
         {
             init();
             scanf ( "%d%d" ,&n,&m);
             int  u,v,w;
             for ( int  i=1;i<=m;i++)
             {
                  scanf ( "%d%d%d" ,&u,&v,&w);
                  add(u,v,w);
                  add(v,u,w);
             }
             int  st,en;
             scanf ( "%d%d" ,&st,&en);
             spfa(st);
             if (dis[en]==INF)//初始化为INF,那么如果终点距离还是INF,那么就说明没有找到最短路径
             {
                 printf ( "Case %d : none!\n" ,cas);
                 printf ( "\n" );
                 continue ;
             }
             cnt=0;
             path[++cnt]=st;
             print(en);
             printf ( "Case %d : %d\n" ,cas,dis[en]);
             for ( int  i=1;i<=cnt;i++)
             {
                 if (i<cnt)  printf ( "%d " ,path[i]);
                 else printf ( "%d\n" ,path[i]);
             }
             printf ( "\n" );
         }
         return 0;
    }

猜你喜欢

转载自blog.csdn.net/dl962454/article/details/70212826