2015ACM/ICPC亞洲區瀋陽站-重現賽 M - Meeting (特殊建邊,最短路)
阿新 • • 發佈:2020-10-09
-
題意:有\(n\)個點,\(m\)個集合,集合\(E_i\)中的點都與集合中的其它點有一條邊權為\(t_i\)的邊,現在問第\(1\)個點和第\(n\)個點到某個點的路徑最短,輸出最短路徑和目標點,如果不滿足條件則輸出\(Evil John\).
-
題解:題目所給的邊數關係太複雜了,我們可以讓每個集合中的所有點都與一個虛擬節點連邊,而這些點兩兩卻不連,然後再去找\(1\)個和第\(n\)個點的最短路徑,不難發現,最終得到的路徑為\(dis[i]/2\),所以我們只要用虛擬節點建邊然後跑兩次dijkstra,最後判斷輸出一下即可.
-
程式碼:
struct misaka{ ll val; ll out; }e; ll t; ll n,m; ll u; ll cost,E; vector<misaka> v[N]; ll dis[2][N]; bool st[N]; vector<ll> ans; void dijkstra(ll start,int op){ me(st,false,sizeof(st)); for(int i=0;i<N;++i) dis[op][i]=INF; dis[op][start]=0; priority_queue<PLL,vector<PLL>,greater<PLL>> h; h.push({0,start}); while(!h.empty()){ auto tmp=h.top(); h.pop(); ll num=tmp.se; ll dist=tmp.fi; if(st[num]) continue; st[num]=true; for(auto w:v[num]){ ll j=w.out; if(dis[op][j]>dist+w.val){ dis[op][j]=dist+w.val; h.push({dis[op][j],j}); } } } } int main() { ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); cin>>t; int p=1; while(t--){ for(ll i=0;i<N;++i){ v[i].clear(); } cin>>n>>m; for(ll i=1;i<=m;++i){ cin>>cost; cin>>E; for(ll j=1;j<=E;++j){ cin>>u; e.out=n+i; e.val=cost; v[u].pb(e); e.out=u; v[n+i].pb(e); } } dijkstra(1,0); dijkstra(n,1); ll res=INF; ans.clear(); for(ll i=1;i<=n;++i){ res=min(res,max(dis[0][i],dis[1][i])); } if(res>=INF){ cout<<"Case #"<<p<<": Evil John"<<endl; } else{ cout<<"Case #"<<p<<": "<<res/2<<endl; for(ll i=1;i<=n;++i){ if(max(dis[0][i],dis[1][i])==res){ ans.pb(i); } } for(int i=0;i<(int)ans.size();++i){ cout<<ans[i]; if(i!=(int)ans.size()-1) cout<<" "; } cout<<'\n'; } p++; } return 0; }