題意
給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\n");
else
{
printf("%d\n",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('\n');
}
}
return 0;
}