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,分别从1与n为起点求一次最短路,对每个点取最大值,最后枚举点取最小值。时间复杂度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;
}
时间: 2024-10-23 16:21:46

HDU 5521 题解的相关文章

hdu 5521 最短路

Meeting Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 1656    Accepted Submission(s): 515 Problem Description Bessie and her friend Elsie decide to have a meeting. However, after Farmer Joh

HDU 5521 Meeting(虚拟节点+最短路)

Meeting Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 1358    Accepted Submission(s): 435 Problem Description Bessie and her friend Elsie decide to have a meeting. However, after Farmer Jo

【hdu 5521】【 2015ACM/ICPC亚洲区沈阳站重现赛】Meeting 题意&题解&代码

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5521 题意: 输入:输入n表示有n个点,输入m表示有m个点集. 接下来m行信息,每行先输入一个t表示这个点集中任意两点费时为t,再输入一个s,表示有s个点在这个点集中,接下来s个数表示这些数在这个点集之中. 现在有两个人,其中一个人住在点1,另一个人住在点n,如果两个人要见面,同时出发,可以走走停停,问需要最少时间是多少,有哪几个点能被当成见面点. 题解: 我们发现这道题如果建好图之后就直接是一个

hdu 5521 Meeting(最短路)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5521 题意:有1-n共n个点,给出m个块(完全图),并知道块内各点之间互相到达花费时间均为ti.已知两人分别在点1和点n,求在哪些点相遇能使得花费时间最短.题解:显然先想到从点1和点n分别求最短路,然后枚举点找出哪些点是相遇花费时间最少的.但是这题边太多了,假设一个完全图里有x个点,那边就有x*(x-1)/2条了,必须化简其边.一个可行的办法是给每个完全图增加两个点,分别为入点和出点,入点向其中的点

HDU 5521.Meeting 最短路模板题

Meeting Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 3361    Accepted Submission(s): 1073 Problem Description Bessie and her friend Elsie decide to have a meeting. However, after Farmer Jo

Hdu 5521 Meeting(建图+最短路)

题目地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=5521 思路:边数太多,不能直接建图.对于每个集合,设置一个虚拟点,对于每个集合中的点u:连一条u->S权值为0的边(点在集合中,花费为0):连一条S->u权值为w的边(从集合中一点到另一点花费w).分别计算从点1到i和从点n到i的最短路,枚举i,则ans=min( ans,max ( dist[0][i],dist[1][i] ) ). #include<queue> #i

hdu - 1237 题解

题意:给出一个数字计算式,包含+,-,*,/四种符号,计算值 题解:最大坑点:不能仅仅判断第一个是0就结束计算,有可能有:0 + 1这样的情况 所以1.判断第一个是否是0,如果是,则判断下一个符号是否是'\n' 2.读入数字和运算符,如果是*,/,取出栈顶元素直接计算完成后压栈,如果是-,将数字相反数压栈,如果是+,将数字压栈. 3.计算栈内元素之和 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm>

2014年北京网络赛 Instrusive HDU 5040 题解 优先队列

网赛的时候看了这道题,发现就是平常的那种基础搜索题. 由于加了一个特殊条件:可以一次消耗3秒或原地停留1秒. 那就不能使用简单的队列了,需要使用优先队列才行. 题意 告诉一副地图:一个起点,一个终点,若干墙,若干监视器,剩下的是空地. 起点,终点,监视器都算空地. 监视器初始值会指定一个方向,共有四个方向. 监视器每秒顺时针转动到下个方向. 监视器视野距离为2. 在监视器的位置或在监视器面向的格子是监视区域. 普通的移动一格需要消耗1秒时间. 在监视器下移动一格需要消耗3秒时间. 如果呆在原地不

hdu - 1231 题解

题意:最大连续子序列问题+输出答案所在的区间 题解:最大连续子序列问题状态转移方程:f[i]=max(a[i],f[i-1]+a[i]) 答案所在区间的话可以在递推求状态的时候,顺便记录一下当前位置所在的序列左端点是谁,最后扫描的时候记录下最优解的位置,然后这个位置就是右端点,记录过的数据就是左端点. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring&g