題意
Graph= {V,E1,E2 },邊有邊權
現在要從S 到達T ,期間有一次機會能夠通過E2 中的邊,其餘時候只能走E1 中的邊,問最短路徑,最短路,如果使用了E2 中的邊,還需輸出經過邊的起點
|V|≤500,|E1|≤1000,|E2|≤1000
解法
分層圖最短路:
一般來說,這道題的做法都是枚舉通過哪一條邊,這種做法可以通過本題,但是對於更大規模的數據來說,例如能夠使用多次機會或者|V|更大 ,那就無法解決了,此時就需要使用分層圖最短路
分層圖最短路是指在可以進行分層圖的圖上解決最短路問題,一般模型是:
在圖上,有k 次機會可以0代價通過一條邊或者經過另外一個邊集之中的邊,問起點與終點之間的最短路徑
解決這類問題的關鍵就是怎麼建立分層圖。一般來說,有以下原則:
①.同一層之間的邊直接按輸入連接
②.有向邊直接從本層的起點連向下一層的終點,無向圖的話就從本層起點連向下層終點,從本層終點連向下層起點
然後從第一層的起點出發,進行最短路求解,最後的答案就是每一層的終點的最短路徑的最小值
另外,一般來說,分層圖問題的邊會比較多,使用spfa 效率不高(k∗nm ),所以一般使用堆優化的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;
}