【UVA11374】Airport Express

題意

  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 int
using 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章