Codeforces 59 E. Shortest Path
問題
n個の都市と、それらをつなぐm本の道がある。
1番の都市からn番の都市へ、使う数の道を最小にして移動したい。
ただし、決められた都市の組(a[i],b[i],c[i])がいくつかあり、
それらをこの順に通ることはできない。
n番の都市へ、使う道の本数を最小にしたときの、訪れる都市を順に出力せよ。
複数ある場合どれを出力してもかまわない。
制約条件
n≦3000
m≦20000
都市の組≦10^5
方針
幅優先探索+経路復元。
ただし、状態として今居る都市ではなく、最後に使った辺を持っておく。
これにより、次の移動で都市の三つ組の条件に反しないかが判定できる。
都市の三つ組は単純にsetなどに入れておけばいい。
ソースコード
struct edge{ int from,to,next; }; edge es[40002]; int e[3000],E; int n,m,k; void add_edge(int u,int v){ es[E]=(edge){ u,v,e[u] }; e[u]=E++; es[E]=(edge){ v,u,e[v] }; e[v]=E++; } set<pair<pi,int> > bad; int prev[40002]; void run() { cin>>n>>m>>k; E=1; rep(i,m){ int s,t; cin>>s>>t; add_edge(s-1,t-1); } rep(i,k){ int a,b,c; cin>>a>>b>>c; bad.insert(mp(mp(a-1,b-1),c-1)); } es[E]=(edge){ -1,0,0 }; queue<int> q; q.push(E++); while(!q.empty()){ int cure=q.front(); q.pop(); int cur=es[cure].to, prv=es[cure].from; if(cur==n-1){ vi ans; for(;cure;cure=prev[cure])ans.pb(es[cure].to); cout<<ans.size()-1<<endl; reverse(all(ans)); rep(i,ans.size())cout<<ans[i]+1<<(i==ans.size()-1?"\n":" "); return; } for(int p=e[cur];p;p=es[p].next){ if(bad.count(mp(mp(prv,cur),es[p].to))||prev[p]!=0)continue; prev[p]=cure; q.push(p); } } cout<<-1<<endl; }