題意: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源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。