首页 > 代码库 > HDU 5521 题解

HDU 5521 题解

题意:给出n个点,John需要和一个住在第n个点的人在某个点碰面,再给出m个集合,每个集合中包含Si个点,这些点两两之间可以以ti时间互达,求两人需花费的最小时间,若无法走到第n个点,则输出Evil John.

2<=N<=100000;1<=ti<=1e9;Si>0;Si<=1e6;

1~6组数据,6000MS

 

算法/思路:

第一次见到这种套路的话还是蛮有趣的,对每个集合中两两点建边显然会被轻松TLE.

使用最短路+虚拟节点:于是我们对每个集合建立一个虚拟节点,在每个集合中的节点与虚拟节点间连一条权值为t的边(最终答案要除以2),然后用spfa或者堆优化dijkstra,分别从1n为起点求一次最短路,对每个点取最大值,最后枚举点取最小值。时间复杂度O((m+n)log(m+n)),由上述描述,0<=m<=1e6.

 

 

#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
int t,n,m,time,s,src;
const int maxn=210000;
vector<pair<int,int>> g[maxn];
int ss;
const long long inf=3e14;
long long ans[maxn];
long long dist[maxn];
int jl[maxn];
int tot;
bool v[maxn];

priority_queue <pair<long long,int>,vector<pair<long long,int> >,greater<pair<long long,int> > > dui;

void dijkstra(){
    for (int i=1;i<=n+m;++i) dist[i]=inf;
    dist[src]=0;
    pair<long long,int> now;
    dui.push(make_pair(0,src));
    memset(v,false,sizeof(v));
    for (int i=1;i<=n+m;++i){
        if (dui.empty()) break;
        now=dui.top();dui.pop();
        while (v[now.second] && !dui.empty()) {now=dui.top();dui.pop();}
        if (v[now.second]) break;
        v[now.second]=true;
        for (int j=0;j<g[now.second].size();++j) if (!v[g[now.second][j].first])
            if (now.first+g[now.second][j].second<dist[g[now.second][j].first])
                {    
                    dist[g[now.second][j].first]=now.first+g[now.second][j].second;dui.push(make_pair(dist[g[now.second][j].first],g[now.second][j].first));
                }
    }
}

int main(){
    scanf("%d",&t);bool tmp;
    for (int q=1;q<=t;++q){
        for (int i=1;i<=maxn;++i) g[i].clear();
        scanf("%d%d",&n,&m);
        for (int i=1;i<=m;++i){
            scanf("%d%d",&time,&s);
            for (int j=1;j<=s;++j) {scanf("%d",&ss);g[i+n].push_back(make_pair(ss,time));g[ss].push_back(make_pair(i+n,time));}
            
        }
        long long pans=inf;
        while(dui.size()) dui.pop();
        src=1;dijkstra();for (int i=1;i<=n;++i) ans[i]=dist[i];
        while(dui.size()) dui.pop();
        src=n;dijkstra();for (int i=1;i<=n;++i) ans[i]=max(dist[i],ans[i]);
        for (int i=1;i<=n;++i) 
            if (pans==inf||ans[i]<pans )  {
                pans=ans[i];tot=1;jl[tot]=i;
            }    else if(ans[i]==pans) jl[++tot]=i;
        printf("Case #%d: ",q);
        if (pans==inf) printf("Evil John\n"); else {
            printf("%lld\n",pans/2);
            for (int i=1;i<=tot-1;++i) printf("%d ",jl[i]);
            printf("%d\n",jl[tot]);
        }
    }
    return 0;
}

 

HDU 5521 题解