2015ACM/ICPC亚洲区沈阳站-重现赛 M - Meeting (特殊建边,最短路)

-
题意:有\(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; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮

浙公网安备 33010602011771号