POJ3114 Countries in War (强连通分量 + 缩点 + 最短路径 + 好题)
Posted zhaop
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ3114 Countries in War (强连通分量 + 缩点 + 最短路径 + 好题)相关的知识,希望对你有一定的参考价值。
题意是说在几个邮局之间传送一份信件,如果出发点和终止点在同一个国家传递,则时间为0,否则让你求花费最少时间,如果不能传到,则输出Nao e possivel entregar a carta。判断邮局是否在同一个国家的依据是发出的信件可以相互到达。
如果直接求最短路则无法判断两个邮局是否在同一个国家,判断两个邮局是否属于同一个国家的标志是在这个国家邮局间可以相互到达,那么这就是强连通了,所以要先缩点判读邮局是否在同一个国家,如果不是,则重新建图,建图的时候要维护好边权,求出最短边权,在用dijkstra求出最短路即可。
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 #include <vector> 6 using namespace std; 7 const int Max = 505; 8 const int INF = 0x3f3f3f3f; 9 int n, m, dfs_clock, scc_cnt, scnt; 10 int g[Max][Max], pre[Max], low[Max], Stack[Max], sccno[Max]; 11 int G[Max][Max]; 12 int head[Max], num; 13 struct Edge 14 { 15 int v, Next; 16 }; 17 Edge edge[Max * Max]; 18 void addEdge(int u, int v) 19 { 20 edge[num].v = v; 21 edge[num].Next = head[u]; 22 head[u] = num++; 23 } 24 void init() 25 { 26 memset(head, -1, sizeof(head)); 27 memset(pre, 0, sizeof(pre)); 28 //memset(low, 0, sizeof(low)); 29 memset(sccno, 0, sizeof(sccno)); 30 scnt = dfs_clock = scc_cnt = num = 0; 31 for (int i = 1; i <= n; i++) 32 for (int j = i; j <= n; j++) 33 { 34 if (i == j) 35 G[i][j] = g[i][j] = 0; 36 else 37 { 38 g[i][j] = g[j][i] = INF; 39 G[i][j] = G[j][i] = INF; 40 } 41 } 42 } 43 void dfs(int u) 44 { 45 pre[u] = low[u] = ++dfs_clock; 46 Stack[scnt++] = u; 47 for (int i = head[u]; i != -1; i = edge[i].Next) 48 { 49 int v = edge[i].v; 50 if (!pre[v]) 51 { 52 dfs(v); 53 low[u] = min(low[u], low[v]); 54 } 55 else if (!sccno[v]) 56 low[u] = min(low[u], pre[v]); 57 } 58 if (low[u] == pre[u]) 59 { 60 scc_cnt++; 61 for (; ;) 62 { 63 int x = Stack[--scnt]; 64 sccno[x] = scc_cnt; 65 if ( x == u) 66 break; 67 } 68 } 69 } 70 void find_scc() 71 { 72 for (int i = 1; i <= n; i++) 73 { 74 if (!pre[i]) 75 dfs(i); 76 } 77 } 78 void build_new_graphic() 79 { 80 for (int i = 1; i <= n; i++) 81 { 82 for (int j = 1; j <= n; j++) 83 { 84 if (i != j && sccno[i] != sccno[j] && g[i][j] != INF) // 不同的连通分量号建立一条有向边。 85 { 86 G[ sccno[i] ][ sccno[j] ] = min(g[i][j], G[ sccno[i] ][ sccno[j] ]); 87 } 88 } 89 } 90 } 91 int dist[Max], vis[Max]; 92 void dijkstra(int start, int goal) 93 { 94 //利用起点start,终点goal来搞,以前做惯了,直接用起点是1来做了 95 for (int i = 1; i <= scc_cnt; i++) 96 dist[i] = G[start][i]; 97 memset(vis, 0, sizeof(vis)); 98 dist[start] = 0; 99 vis[start] = 1; 100 for (int i = 2; i <= scc_cnt; i++) 101 { 102 int minn = INF, pos = 1; // 这里初始化pos为1,否则当下面的循环不满足条件是,执行vis[pos]会出错 103 for (int j = 1; j <= scc_cnt; j++) 104 { 105 if (!vis[j] && minn > dist[j]) 106 { 107 minn = dist[j]; 108 pos = j; 109 } 110 } 111 vis[pos] = 1; 112 for (int j = 1; j <= scc_cnt; j++) 113 { 114 if (!vis[j] && dist[j] > dist[pos] + G[pos][j]) 115 dist[j] = dist[pos] + G[pos][j]; 116 } 117 } 118 if (dist[goal] != INF) 119 printf("%d\\n", dist[goal]); 120 else 121 printf("Nao e possivel entregar a carta\\n"); 122 } 123 int main() 124 { 125 while (scanf("%d%d", &n, &m) != EOF) 126 { 127 if (n == 0 && m == 0) 128 break; 129 init(); 130 int u, v, c; 131 for (int i = 1; i <= m; i++) 132 { 133 scanf("%d%d%d", &u, &v, &c); 134 if (g[u][v] > c) 135 { 136 g[u][v] = c; // 判断重边 137 } 138 addEdge(u, v); 139 } 140 find_scc(); // 找强连通分量 141 //cout << scc_cnt << endl; 142 build_new_graphic(); // 重新构图 143 144 int k; 145 scanf("%d", &k); 146 while (k--) 147 { 148 scanf("%d%d", &u, &v); 149 if (sccno[u] == sccno[v]) // 同一连通分量直接输出 150 printf("0\\n"); 151 else 152 { 153 dijkstra(sccno[u], sccno[v]); 154 } 155 } 156 printf("\\n"); 157 } 158 159 return 0; 160 }
以上是关于POJ3114 Countries in War (强连通分量 + 缩点 + 最短路径 + 好题)的主要内容,如果未能解决你的问题,请参考以下文章