题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5521
分析:一个1到n的图,图被分成了几个集合,集合 i 内的点之间到达的时间是 Wi ,找一个点是的从1点的人和从n点的人接头,时间最短,如果多种答案,把点都输出。
解题思路:不可能在点与点之间建图,这样开销太大了,每加一个集合,可以新加一个点,这样最多不会超过2*maxn,所以链式前向星开这么大即可;
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define LL long long
#define INF LONG_LONG_MAX
using namespace std;
const int maxn=1e6+10;
struct Edge{
int next,w,to;
}edge[maxn*2];
LL dis[maxn],vis[maxn],dis2[maxn];
int head[maxn],n,m,ecnt;
void add(int u,int v,int w)
{
edge[ecnt].next=head[u];
edge[ecnt].to=v;
edge[ecnt].w=w;
head[u]=ecnt++;
}
struct HeapNode {
LL dis;
int u;
friend bool operator < (HeapNode A, HeapNode B){
return A.dis > B.dis;
}
};
void Dj(int s,int ed)
{
priority_queue <HeapNode> q;
for(int i=0;i<=ed;i++)
{
dis[i]=INF;
vis[i]=0;
}
dis[s]=0;
HeapNode hh;
hh.dis=0; hh.u=s;
q.push(hh);
while(!q.empty())
{
hh=q.top(); q.pop();
vis[hh.u]=1;
for(int i=head[hh.u];i!=-1;i=edge[i].next)
{
if(!vis[edge[i].to] && dis[edge[i].to]>dis[hh.u]+edge[i].w)
{
dis[edge[i].to]=dis[hh.u]+edge[i].w;
HeapNode hp;
hp.dis=dis[edge[i].to]; hp.u=edge[i].to;
q.push(hp);
}
}
}
}
int main()
{
int t;
int cas=0;
int Next;
scanf("%d",&t);
while(t--)
{
ecnt=0;
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
Next=n+1;
for(int i=0;i<m;i++)
{
int u,w,s;
scanf("%d%d",&w,&s);
for(int j=0;j<s;j++)
{
scanf("%d",&u);
add(u,Next,w);
add(Next,u,0);
}
Next++;
}
Dj(1,n+m+1);
for(int i=0;i<=n;i++)
dis2[i]=dis[i];
Dj(n,n+m+1);
LL ans=INF;
for(int i=1;i<=n;i++)
ans=min(ans,max(dis2[i],dis[i]));
printf("Case #%d: ",++cas);
if(ans<INF)
{
printf("%lld\n",ans);
int flag=0;
for(int i=1;i<=n;i++)
{
if(max(dis[i],dis2[i])==ans)
{
if(flag)
printf(" ");
printf("%d",i);
flag=1;
}
}
printf("\n");
}
else
printf("Evil John\n");
}
return 0;
}