2015沈阳站-Meeting 最短路
http://acm.hdu.edu.cn/showproblem.php?pid=5521
题目大意:A,B两个人分别在1和n区。给出区之间有联系的图以及到达所需时间。求两个人见面最短时间以及在哪个区碰面(可有多个)。多个区被当成一个集合(set),集合中的点互相到达时间相同,并且一定能互达。
思路:在于边的数量庞大。需要着手解决的问题是如何建图使得边的数目减小。
题目的特殊点在于:每个区域内部的点点距离是相同的。
所以,构造虚拟结点,解决边数过多的问题。 (n*(n-1))/2 ---------> n+1 是一个很明显的优化
然后从1,n进行两次spfa,第一次spfa进行完,如果1,n不联通(因为是无向边)直接输出 Evil John。(不卡spfa😢)
之后进行枚举,选择最小的时间。
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 #include <cmath> 5 #include <cstdio> 6 #include <vector> 7 #include <queue> 8 #include <set> 9 #include <map> 10 #include <stack> 11 #define ll long long 12 //#define local 13 14 using namespace std; 15 16 const int MOD = 1e9+7; 17 const long long inf = 0x3f3f3f3f3f; 18 const int maxedge = 2e6+5; 19 const int maxnode = 1e6+1e5+5; 20 struct Edge { 21 int u, v, w; 22 int pre; 23 } edge[maxedge]; 24 ll dist[maxnode]; 25 ll dist1[maxnode]; 26 ll dist2[maxnode]; 27 int inque[maxnode]; 28 int point[maxnode]; 29 int a[1000005]; 30 int n, m, cnt, node; 31 ll t, tmp; 32 vector<int> v; 33 34 void AddEdge(int u, int v, int w) { 35 edge[cnt].u = u; 36 edge[cnt].v = v; 37 edge[cnt].w = w; 38 edge[cnt].pre = point[u]; 39 point[u] = cnt++; 40 } 41 42 void spfa (int start) { 43 for (int i = 0; i <= n+m+1; i++) dist[i] = inf; 44 memset(inque, 0, sizeof(inque)); 45 dist[start] = 0; 46 queue<int> q; 47 q.push(start); 48 while (q.size()) { 49 int u = q.front(); 50 q.pop(); 51 inque[u] = 0; 52 for (int i = point[u]; i != -1; i = edge[i].pre) { 53 int v = edge[i].v; 54 if(dist[v] > dist[u]+edge[i].w) { 55 dist[v] = dist[u]+edge[i].w; 56 if(!inque[v]) { 57 inque[v] = 1; 58 q.push(v); 59 } 60 } 61 } 62 } 63 } 64 65 int main() { 66 #ifdef local 67 if(freopen("/Users/Andrew/Desktop/data.txt", "r", stdin) == NULL) printf("can't open this file!\n"); 68 #endif 69 int T; 70 int w,s; 71 int kase = 0; 72 scanf("%d", &T); 73 while (T--) { 74 scanf("%d%d", &n, &m); 75 cnt = 0; 76 node = n+1; 77 memset(point, -1, sizeof(point)); 78 for (int i = 0; i < m; ++i) { 79 scanf("%d%d", &w, &s); 80 for (int j = 0; j < s; ++j) { 81 scanf("%d", &a[j]); 82 AddEdge(a[j], node, w); 83 AddEdge(node, a[j], w); 84 } 85 node++; 86 } 87 printf("Case #%d: ", ++kase); 88 spfa(1); 89 if (dist[n] == inf) { 90 printf("Evil John\n"); 91 continue; 92 } 93 for (int i = 1; i <= n; ++i) dist1[i] = dist[i]; 94 spfa(n); 95 for (int i = 1; i <= n; ++i) dist2[i] = dist[i]; 96 t = inf; 97 for (int i = 1; i <= n; ++i) { 98 tmp = max(dist1[i], dist2[i]); 99 t = min(t, tmp); 100 } 101 v.clear(); 102 for (int i = 1; i <= n; ++i) { 103 if (t == max(dist1[i], dist2[i])) 104 v.push_back(i); 105 } 106 t /= 2; 107 cout<< t <<endl; 108 for (int i = 0; i < v.size(); i++) { 109 if(!i) printf("%d", v[i]); 110 else printf(" %d", v[i]); 111 } 112 printf("\n"); 113 } 114 #ifdef local 115 fclose(stdin); 116 #endif 117 return 0; 118 }