题意
给m个由图中结点组成的点集,点集中的点两两连通且距离为相等的ti。现有两人分别从1和N点处同时出发吗,问能否相遇以及相遇的最短时间。
分析
很容易想到直接分别以点1和点N为起始点求最短路,再遍历各个点即可求得最短相遇时间。然而建图上却有问题:这个题中的边是以点集的形式给出,极端情况下可能会出现有1E12条边的稠密图。
这时就要利用点集中的点之间距离相等这个性质,拆点来建图。将点集抽象成一个点,将点集中的每个连一条长为ti/2的边到这个点集的点。 这样做可以大大减少边的数量。另外为了防止出现浮点数,可以直接把每个边变成ti而不是ti/2最后在最短时间上除以2就可以了
AC代码
//HDU 5521 Meeting
//AC 2016-08-10 16:43:30
//Shortest Path
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <set>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <list>
#include <sstream>
#include <stack>
using namespace std;
#define cls(x) memset(x,0,sizeof x)
#define inf(x) memset(x,0x3f,sizeof x)
#define neg(x) memset(x,-1,sizeof x)
#define ninf(x) memset(x,0xc0,sizeof x)
#define st0(x) memset(x,false,sizeof x)
#define st1(x) memset(x,true,sizeof x)
#define INF 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define input(x) scanf("%d",&(x))
#define bug cout<<"here"<<endl;
//#define debug
int T;
int n,m;
struct node
{
int pos;
int dist;
bool operator< (const node &rhs) const
{
return dist>rhs.dist;
}
}p,q;
vector<node> G[1100100];
int dist1[1100100],dist2[1100100];
void dijkstra(int beg,int dist[])
{
priority_queue<node> DIJ;
p.pos=beg;p.dist=0;
dist[beg]=0;
DIJ.push(p);
while(DIJ.size())
{
p=DIJ.top();DIJ.pop();
if(dist[p.pos]>p.dist) continue;
for(int i=0;i<G[p.pos].size();++i)
{
q.pos=G[p.pos][i].pos;
q.dist=p.dist+G[p.pos][i].dist;
if(dist[q.pos]>q.dist)
{
dist[q.pos]=q.dist;
DIJ.push(q);
}
}
}
return;
}
int main()
{
#ifdef debug
freopen("E:\Documents\code\input.txt","r",stdin);
freopen("E:\Documents\code\output.txt","w",stdout);
#endif
int T;input(T);
for(int kase=1;kase<=T;++kase)
{
scanf("%d %d",&n,&m);
for(int i=0;i<=n+m;++i) G[i].clear();
int t,s,a;
for(int i=1;i<=m;++i)
{
scanf("%d %d",&p.dist,&s);
for(int j=0;j<s;++j)
{
input(a);p.pos=i+n;
G[a].push_back(p);
p.pos=a;
G[i+n].push_back(p);
}
}
inf(dist1);inf(dist2);
dijkstra(1,dist1);dijkstra(n,dist2);
int res=INF;
for(int i=1;i<=n;++i)
res=min(res,max(dist1[i],dist2[i]));
printf("Case #%d: ",kase);
if(res>=INF) printf("Evil John
");
else
{
printf("%d
",res/2);
bool first=1;
for(int i=1;i<=n;++i)
{
if(max(dist1[i],dist2[i])==res)
{
if(!first) putchar(' ');
first=0;
printf("%d",i);
}
}
putchar('
');
}
}
return 0;
}