题意:node
给你n(n<=1e5)个点,m个彻底图集合(每一个集合包含权值v,集合中的点数cnt和集合里的点的标号,表示集合里的点构成无向彻底图,两点之间权值为v(时间))。c++
保证集合中全部的点的数量不超过1e6。算法
两我的分别从1点和n点走,只能够在一个点相遇(一我的能够等另外一我的),求最短相遇时间和最短期的前提下在哪些编号的点相遇时间都是最短。优化
若是没法相遇,输出“Evil John”。spa
思路:.net
比赛的时候没作出来,不过看了题解以后,感受构图真是巧妙。可能很简单吧,比赛的时候过了好多人,可是我却没想到。。。code
考虑题目中特殊条件“保证集合中全部的点的数量不超过1e6。”,显然不能每一个集合每一个点相互建边。所以要将集合建边。blog
可是咱们要求的是1点和n点的单源最短路 怎么能用集合建图呢???get
假设咱们如今从1点开始走,若是想走到另外一个点,只能走集合。因而,咱们把集合编号 n+1~n+m+1。
对于集合中每一个点 向集合建边 add(x,n+i,v);add(n+i,x,0)。这样只要一个非这个集合中的点想通过集合中的点,就一定要通过这条边,即花费时间。进入这个集合后,走向中集合中的任何点花费就都为0了(由于进来的点已经加了花费,走任何点都至关于直接走过去,花费就是v)。这样通过这个集合时时间就仅增长了v。
而后套个快一点的堆优化的Dijkstra算法板子分别求两次单源最短路,而后枚举每一个相遇的点,取个最小值,对于相遇时间等于最小值的点就能够直接输出了。
代码:
#include<bits/stdc++.h> #define ll long long #define inf 0x3f3f3f3f3f3f3f3fLL #define pa pair<int,int> using namespace std; const int maxn = 2200010; struct node { int to,next; ll v; }; struct Dijkstra { node edge[maxn]; int cnt,head[maxn],n; ll dis[maxn]; void init(int nn) { n=nn; cnt=0; for(int i=0;i<=n;i++) head[i]=0; } void add(int u,int v,int w) { cnt++; edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].v=w; } void dijkstra(int s) { priority_queue<pa,vector<pa>,greater<pa> >q; int i,now; for (i=1;i<=n;i++) dis[i]=inf; dis[s]=0; q.push(make_pair(0,s)); while (!q.empty()) { now=q.top().second; q.pop(); for (i=head[now];i;i=edge[i].next) if (dis[now]+edge[i].v<dis[edge[i].to]) { dis[edge[i].to]=dis[now]+edge[i].v; q.push(make_pair(dis[edge[i].to],edge[i].to)); } } } }D1,DN; int n,m; ll v; int main() { int T,cas=1; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); D1.init(n+m+1); DN.init(n+m+1); for(int i=0;i<m;i++) { int cnt; scanf("%lld%d",&v,&cnt); for(int j=0;j<cnt;j++) { int x; scanf("%d",&x); D1.add(x,n+i+1,v); D1.add(n+i+1,x,0); DN.add(x,n+i+1,v); DN.add(n+i+1,x,0); } } D1.dijkstra(1); DN.dijkstra(n); ll mi=inf; for(int i=1;i<=n;i++) { D1.dis[i]=max(D1.dis[i],DN.dis[i]); mi=min(mi,D1.dis[i]); } printf("Case #%d: ",cas++); if(mi==inf) puts("Evil John"); else { printf("%d\n",mi); bool fg=0; for(int i=1;i<=n;i++) if(mi==D1.dis[i]){ if(!fg) printf("%d",i),fg=1; else printf(" %d",i); } puts(""); } } return 0; }
本文分享 CSDN - LSD20164388。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。