【UVA11374】Airport Express

来源:互联网 发布:dom编程艺术第二版txt 编辑:程序博客网 时间:2024/05/02 01:37

题意

  Graph={VE1E2},边有边权
  现在要从S到达T,期间有一次机会能够通过E2中的边,其余时候只能走E1中的边,问最短路径,最短路,如果使用了E2中的边,还需输出经过边的起点
  |V|500|E1|1000|E2|1000

解法

分层图最短路:
  一般来说,这道题的做法都是枚举通过哪一条边,这种做法可以通过本题,但是对于更大规模的数据来说,例如能够使用多次机会或者|V|,那就无法解决了,此时就需要使用分层图最短路
  分层图最短路是指在可以进行分层图的图上解决最短路问题,一般模型是:
  在图上,有k次机会可以0代价通过一条边或者经过另外一个边集之中的边,问起点与终点之间的最短路径
  解决这类问题的关键就是怎么建立分层图。一般来说,有以下原则:
  ①.同一层之间的边直接按输入连接
  ②.有向边直接从本层的起点连向下一层的终点,无向图的话就从本层起点连向下层终点,从本层终点连向下层起点
  然后从第一层的起点出发,进行最短路求解,最后的答案就是每一层的终点的最短路径的最小值
  另外,一般来说,分层图问题的边会比较多,使用spfa效率不高(knm),所以一般使用堆优化的Dijkstra,可以在nlogn的时间内解决

复杂度

O(T*2*n*log(2*n))

代码

#include<iostream>#include<cstdlib>#include<cstring>#include<cstdio>#define ls 2*k#define rs 2*k+1#define Rint register int#define Lint long long intusing namespace std;const int INF=0x3f3f3f3f;const int E=50010;const int N=5010;struct Edge{    int next;    int u,v,w;}t[E];struct Head{    int a[N*10],dis[N*10];    int tail;    void Swap(int x,int y)    {        swap( a[x],a[y] );        swap( dis[x],dis[y] );    }    void insert(Rint k,Rint w)    {        a[++tail]=k,dis[tail]=w;        int tmp=tail;        while( tmp>=2 )        {            if( dis[tmp]<dis[tmp/2] )            {                Swap( tmp,tmp/2 );                tmp=tmp/2;            }            else   break ;        }    }    void update(Rint k)    {        int tmp=k;        if( ls<=tail && dis[ls]<dis[tmp] )   tmp=ls;        if( rs<=tail && dis[rs]<dis[tmp] )   tmp=rs;        if( tmp!=k )        {            Swap( tmp,k );            update( tmp );        }    }    void pop()    {        Swap( 1,tail ),tail--;        update( 1 );    }    int top()    {        return a[1];    }    bool empty()    {        return !tail;    }}q;int head[N],num;int dis[N],vis[N];int Pre[N],s[N];int n,m,k,S,T;int cnt;void add(int u,int v,int w){    t[++num]=(Edge){ head[u],u,v,w };    head[u]=num;}void work(){    int tmp;    for(int i=1;i<=2*n;i++)   dis[i]=INF,vis[i]=0;    dis[S]=0,q.insert( S,0 );    while( !q.empty() )    {        tmp=q.top(),q.pop();        if( vis[tmp] )   continue ;        vis[tmp]=1;        for(int i=head[tmp],x; i ;i=t[i].next)        {            x=t[i].v;            if( dis[x]>dis[tmp]+t[i].w && !vis[x] )            {                Pre[x]=i;                dis[x]=dis[tmp]+t[i].w;                q.insert( x,dis[x] );            }        }    }}int main(){    int u,v,w,C=0;    while( scanf("%d%d%d",&n,&S,&T)!=EOF )    {        if( ++C>1 )   printf("\n");        cnt=num=0;        memset( Pre,0x0,sizeof Pre );        memset( head,0x0,sizeof head );        scanf("%d",&m);        for(int i=1;i<=m;i++)        {            scanf("%d%d%d",&u,&v,&w);            add( u,v,w ),add( v,u,w );            add( u+n,v+n,w ),add( v+n,u+n,w );        }        scanf("%d",&k);        for(int i=1;i<=k;i++)        {            scanf("%d%d%d",&u,&v,&w);            add( u,v+n,w ),add( v,u+n,w );        }        work();        if( dis[T]<dis[T+n] )        {            u=0,v=dis[T],s[++cnt]=T;            for(int i=Pre[T]; i ;i=Pre[t[i].u])            {                s[++cnt]= t[i].u>n ? t[i].u-n : t[i].u ;                if( t[i].v>n )   u=t[i].u;            }        }        else        {            u=0,v=dis[T+n],s[++cnt]=T;            for(int i=Pre[T+n]; i ;i=Pre[t[i].u])            {                s[++cnt]= t[i].u>n ? t[i].u-n : t[i].u ;                if( t[i].v>n )   u=t[i].u;            }        }        printf("%d",s[cnt]);        for(int i=cnt-1;i>=1;i--)   printf(" %d",s[i]);        printf("\n");        if( u )   printf("%d\n",u);        else   printf("Ticket Not Used\n");        printf("%d\n",v);    }    return 0;}
原创粉丝点击