分析:优先队列维护当前节点的最短路,每次更新当前节点所在的所有集合里面的所有节点的最短路,扔到优先队列里面,标记这个集合找过了。
复杂度: o(∑Si)=o(106)
代码:
#include <bits/stdc++.h>
#define LL long long
#define FOR(i,x,y) for(int i = x;i < y;++ i)
#define IFOR(i,x,y) for(int i = x;i > y;-- i)
using namespace std;
typedef vector <int> VT;
typedef pair <int,int> pii;
const LL inf = (1LL<<62);
const int maxm = 1000100;
const int maxn = 100010;
VT block[maxm];
VT node[maxn];
int n,m;
LL t[maxm],d[2][maxn];
bool visb[maxm];
void init(){
scanf("%d%d",&n,&m);
FOR(i,0,n+1) node[i].clear();
FOR(i,1,m+1){
int sz;
scanf("%I64d%d",&t[i],&sz);
block[i].clear();
int id;
FOR(j,0,sz){
scanf("%d",&id);
block[i].push_back(id);
node[id].push_back(i);
}
}
FOR(i,1,n+1) d[0][i] = d[1][i] = inf;
}
void dijkstra(int st,int op){
memset(visb,false,sizeof(visb));
d[op][st] = 0;
priority_queue <pii,vector<pii>,greater<pii> > q;
q.push(make_pair(d[op][st],st));
while(!q.empty()){
pii p = q.top(); q.pop();
int u = p.second;
FOR(i,0,(int)node[u].size()){
int b = node[u][i];
if(visb[b]) continue;
visb[b] = true;
FOR(j,0,(int)block[b].size()){
int v = block[b][j];
if(d[op][u] + t[b] < d[op][v]){
d[op][v] = d[op][u] + t[b];
q.push(make_pair(d[op][v],v));
}
}
}
}
}
void work(){
dijkstra(1,0);
dijkstra(n,1);
LL res = inf;
vector <int> ans;
FOR(i,1,n+1) {LL temp = max(d[0][i],d[1][i]); res = min(temp,res);}
if(res == inf) {printf("Evil John\n");return;}
FOR(i,1,n+1) if(res == max(d[0][i],d[1][i])) ans.push_back(i);
printf("%I64d\n%d",res,ans[0]);
FOR(i,1,(int)ans.size()){
printf(" %d",ans[i]);
}
printf("\n");
}
int main()
{
//freopen("test.in","r",stdin);
int T,tCase = 0; scanf("%d",&T);
while(T--){
printf("Case #%d: ",++tCase);
init();
work();
}
return 0;
}