2015 ACM/ICPC 瀋陽區域賽 現場賽 M—Meeting 【Dijkstra】
阿新 • • 發佈:2018-12-13
題意:
給你n(n<=1e5)個點,m個關係:每個關係代表一個集合,包含權值v,表示該集合集合中兩兩的距離,還有集合的點的個數cnt和集合裡的點的標號,相當於一個有距離的完全圖。
保證集合中所有的點的數量不超過1e6。
兩個人分別從1點和n點走,只可以在一個點相遇(一個人可以等另一個人),求最短相遇時間和最短時間的前提下在哪些編號的點相遇時間都是最短。
如果無法相遇,輸出“Evil John”。
分析:
一看就是兩個點的Dijkstra求最短路徑,但是如何建圖就很困難。因為一個完全圖需要建n*(n-1)/2的邊,容易超時,只能用組的方式建邊。對於集合中每個點 向集合的中心點(n+i)建邊 add(x,n+i,v);add(n+i,x,0)。保證集合中的任意兩個點的距離是v。
圖建的很巧妙。
程式碼:
#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,0); D1.add(n+i+1,x,v); DN.add(x,n+i+1,0); DN.add(n+i+1,x,v); } } 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; }