返回顶部

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;
    }
    
posted @ 2020-10-09 10:51  _Kolibri  阅读(149)  评论(0)    收藏  举报