题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5521
题意:
有一个n个点的图,会给你m个集合,每个集合内的点,距离都是t[i]
然后A在点1,B在点n,然后让你找到一个点,使得max(disA[i],disB[i])最小
如果有多个答案,按照字典序输出所有答案
如果没有答案输出Evil John
思路:
两次dijkstra,注意不能直接建边。对于当前点所在的集合,要是之前没有遍历过,就遍历集合内所有的点,更新d[i]。
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <queue> 5 #include <map> 6 using namespace std; 7 typedef __int64 LL; 8 typedef pair <LL, int> P; 9 const int N = 1e5 + 5; 10 LL d1[N], d2[N], inf = 1e16; 11 int a[N]; 12 vector <int> G[N], belong[N]; 13 bool vis[N]; 14 void dij(int s, int n) { 15 for(int i = 1; i <= n; ++i) { 16 d1[i] = inf; 17 vis[i] = false; 18 } 19 d1[s] = 0; 20 priority_queue <P, vector<P>, greater<P> > que; 21 while(!que.empty()) { 22 que.pop(); 23 } 24 que.push(make_pair(d1[s], s)); 25 while(!que.empty()) { 26 P temp = que.top(); 27 int u = temp.second; 28 que.pop(); 29 if(d1[u] < temp.first) 30 continue; 31 for(int i = 0; i < belong[u].size(); ++i) { 32 int x = belong[u][i]; 33 if(vis[x]) //集合之前遍历过 34 continue; 35 vis[x] = true; 36 for(int j = 0; j < G[x].size(); ++j) { 37 int v = G[x][j]; 38 if(v != u && d1[v] > d1[u] + a[x]) { 39 d1[v] = d1[u] + a[x]; 40 que.push(make_pair(d1[v], v)); 41 } 42 } 43 } 44 } 45 } 46 void dij2(int s, int n) { 47 for(int i = 1; i <= n; ++i) { 48 d2[i] = inf; 49 vis[i] = false; 50 } 51 d2[s] = 0; 52 priority_queue <P, vector<P>, greater<P> > que; 53 while(!que.empty()) { 54 que.pop(); 55 } 56 que.push(make_pair(d2[s], s)); 57 while(!que.empty()) { 58 P temp = que.top(); 59 int u = temp.second; 60 que.pop(); 61 if(d2[u] < temp.first) 62 continue; 63 for(int i = 0; i < belong[u].size(); ++i) { 64 int x = belong[u][i]; 65 if(vis[x]) //集合之前遍历过 66 continue; 67 vis[x] = true; 68 for(int j = 0; j < G[x].size(); ++j) { 69 int v = G[x][j]; 70 if(v != u && d2[v] > d2[u] + a[x]) { 71 d2[v] = d2[u] + a[x]; 72 que.push(make_pair(d2[v], v)); 73 } 74 } 75 } 76 } 77 } 78 void init(int n) { 79 for(int i = 1; i <= n; ++i) { 80 G[i].clear(); 81 belong[i].clear(); 82 } 83 } 84 vector <int> res; 85 int main() 86 { 87 int t, n, m; 88 scanf("%d", &t); 89 for(int ca = 1; ca <= t; ++ca) { 90 scanf("%d %d", &n, &m); 91 init(n); 92 res.clear(); 93 int num, x; 94 for(int k = 1; k <= m; ++k) { 95 scanf("%d %d", &a[k], &num); 96 for(int i = 1; i <= num; ++i) { 97 scanf("%d", &x); 98 G[k].push_back(x); //集合k内的点 99 belong[x].push_back(k); //点x所在的集合 100 } 101 } 102 dij(1, n); 103 dij2(n, n); 104 LL ans = inf; 105 for(int i = 1; i <= n; ++i) { 106 ans = min(ans, max(d1[i], d2[i])); 107 } 108 printf("Case #%d: ", ca); 109 if(ans == inf) { 110 printf("Evil John "); 111 } else { 112 for(int i = 1; i <= n; ++i) { 113 if(d1[i] <= ans && d2[i] <= ans) { 114 res.push_back(i); 115 } 116 } 117 int xx = res.size(); 118 printf("%I64d ", ans); 119 for(int i = 0; i < xx - 1; ++i) { 120 printf("%d ", res[i]); 121 } 122 printf("%d ", res[xx - 1]); 123 } 124 } 125 return 0; 126 }