题目大意:有n个点,两个人,一个人在点1,另一个人在点n。他们两人要见上一面。两人同时出发,问在哪相遇花费时间最短,答案可能有多个。先到的人可以等后到的人。
思路:拿到这题很自然的就想到迪杰斯特拉求最短路,从1到n求一遍求得数组dist_1,再从n到1求一遍得数组dist_n。最后遍历一下两个数组找到min(max(dist_1[i],dist_n[i]))。但这样做会T。为什么呢?看题目的输入,题目给出若干个集合,在这集合中每个点之间的距离都为t。如此,如果要是像往常一样之间在a,b上建边的话边的数量就会很大。可以想象一下如果集合中点的数目为4甚至更多的话边的个数。所以我们需要加点!例如,我们现在有一个集合,里面有4个点1~4。那么我们加一个点A,并建立从A到1的边,A到2的边.....以此类推...这样我们只需要建4条边就可以构造出图。需要注意的是...这样建图得出的结果比实际的结果要多出一倍,可以自己走走就知道了。最后就是简单的最短路求解了。
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e6+7;
const ll inf =1e18+7;
struct d
{
int next,to;
ll val;
}edge[maxn<<1];
int head[maxn];
int cnt;
void addEdge(int from,int to,ll val)
{
edge[cnt].to=to;
edge[cnt].val=val;
edge[cnt].next=head[from];
head[from]=(cnt++);
}
ll dist_1[maxn];
ll dist_n[maxn];
struct ha
{
int id;
ll val;
bool operator <(const ha &a) const
{
return val>a.val;
}
}node;
void solve(int start,ll* dist)
{
bool vis[maxn]={0};
for(int i=0;i<maxn;i++) dist[i]=inf;
dist[start]=0;
node.id=start; node.val=0;
priority_queue<ha> qu; qu.push(node);
while(!qu.empty())
{
ha now=qu.top();
int pos=now.id;
qu.pop();
if(vis[pos]) continue;
vis[pos]=1;
for(int i=head[pos];i;i=edge[i].next)
{
int tto=edge[i].to;
if(!vis[tto]&&dist[tto]>now.val+edge[i].val)
{
dist[tto]=now.val+edge[i].val;
node.id=tto; node.val=dist[tto];
qu.push(node);
}
}
}
}
int ans[maxn];
int ans_num;
int main()
{
int T; scanf("%d",&T);
int c=0;
while(T--)
{
memset(head,0,sizeof(head));
memset(edge,0,sizeof(edge));
memset(ans,0,sizeof(ans));
cnt=ans_num=0;
int n,m; scanf("%d%d",&n,&m);
int extra=n;
while(m--)
{
extra++;
ll t; int s; scanf("%lld%d",&t,&s);
for(int i=0;i<s;i++)
{
int a; scanf("%d",&a);
addEdge(extra,a,0);
addEdge(a,extra,t);
}
}
solve(1,dist_1);
solve(n,dist_n);
printf("Case #%d: ",++c);
if(dist_1[n]==inf) printf("Evil John\n");
else
{
ll mmin=inf;
for(int i=1;i<=n;i++)
{
ll temp=max(dist_1[i],dist_n[i]);
if(temp<mmin)
{
mmin=temp;
ans_num=0;
ans[ans_num++]=i;
}
else if(temp==mmin) ans[ans_num++]=i;
}
printf("%lld\n%d",mmin,ans[0]);
for(int i=1;i<ans_num;i++)
printf(" %d",ans[i]);
printf("\n");
}
}
return 0;
}