poj 3114 强连通+缩点+最短路
1 /* 2 题意:给出一个N个城市组成的有向图,从i城市发送letter到j城市可以通过post/fiber,通过fiber发送需要0 hour, 3 通过post需要h hour,N个城市可以分为X个国家,组成国家的条件是几个城市之间可以通过post使得这几个城市强连 4 通,然后属于同一个国家的两个城市可以采取fiber的方式发送letter,并且属于同一个国家的城市任意两两之间会有 5 fiber相通,不同国家的城市之间则只能通过post发送,给出k个查询,问从a城市发送letter到b城市最短时间是多少 6 7 题解:强连通+缩点+最短路 8 此处的求有向图的强连通分量用的是kosaraju算法 9 显然同一个国家内发送letter只需要通过fiber,则时间消耗为0,因此,通过求强连通分量找出同一个国家的点,然后 10 缩点组成一个只能通过post发送消息的图,然后用最短路即可求出结果。 11 */ 12 #include <cstdio> 13 #include <cstring> 14 15 const int MAXINT = 1e8; 16 const int MAXV = 505; 17 18 int g[MAXV][MAXV], dfn[MAXV], num[MAXV], n, scc, cnt; // 原图,后续遍历入栈顺序,记录强连通点,总点数,连通分量个数,指向栈的顶部 19 int map[MAXV][MAXV]; // 缩点后的图 20 21 void dfs(int k) 22 { 23 num[k] = 1; 24 for(int i=1; i<=n; i++) 25 if(g[k][i]!=-1 && !num[i]) 26 dfs(i); 27 dfn[++cnt] = k; //记录第cnt个出栈的顶点为k 28 } 29 void ndfs(int k) 30 { 31 num[k] = scc; //本次DFS染色的点,都属于同一个scc,用num数组做记录 32 for(int i=1; i<=n; i++) 33 if(g[i][k] != -1 && !num[i]) //注意我们访问的原矩阵的对称矩阵 34 ndfs(i); 35 } 36 void kosaraju() 37 { 38 scc = 0; 39 cnt = 0; 40 memset(num,0,sizeof(num)); 41 for(int i=1; i<=n; i++) //DFS求得拓扑排序 42 if(!num[i]) 43 dfs(i); 44 memset(num, 0, sizeof(num)); 45 /* 我们本需对原图的边反向,但由于我们使用邻接矩阵储存图,所以反向的图的邻接矩阵 46 即原图邻接矩阵的对角线对称矩阵,所以我们什么都不用做,只需访问对称矩阵即可*/ 47 for(int i=n; i>=1; i--) 48 if(!num[dfn[i]]) 49 { //按照拓扑序进行第二次DFS 50 scc++; 51 ndfs(dfn[i]); 52 } 53 } 54 55 void build_map() // 建图 56 { 57 for(int i=1; i<=scc; i++) 58 for(int j=1; j<=scc; j++) 59 map[i][j] = MAXINT; 60 for(int i=1; i<=n; i++) 61 for(int j=1; j<=n; j++) 62 if (g[i][j] != -1 && num[i] != num[j]) 63 { 64 // 此处注意是num[i],因为是缩点后的图 65 if (map[num[i]][num[j]] == MAXINT || map[num[i]][num[j]] > g[i][j]) 66 map[num[i]][num[j]] = g[i][j]; 67 } 68 } 69 70 int dis[MAXV]; 71 bool vis[MAXV]; 72 73 void dij(int start,int end) 74 { 75 int min,min_f; 76 for(int i=1; i<=scc; i++) 77 { 78 dis[i] = map[start][i]; 79 vis[i] = false; 80 } 81 vis[start] = true; 82 dis[start] = 0; 83 for(int i=1; i<scc; i++) 84 { 85 min=MAXINT; 86 min_f=1; 87 for(int j=1; j<=scc; j++) 88 { 89 if(!vis[j] && min>dis[j]) 90 { 91 min=dis[j]; 92 min_f=j; 93 } 94 } 95 vis[min_f]=true; 96 for(int j=1; j<=scc; j++) 97 { 98 if(!vis[j] && dis[j] > dis[min_f] + map[min_f][j]) 99 dis[j] = dis[min_f] + map[min_f][j]; 100 } 101 } 102 if(dis[end] == MAXINT) 103 printf("Nao e possivel entregar a carta\n"); 104 else 105 printf("%d\n",dis[end]); 106 } 107 int main(void) 108 { 109 int e,k,o,d; 110 while (~scanf("%d%d",&n,&e) && n) 111 { 112 memset(g,-1,sizeof(g)); 113 while (e--) 114 { 115 int u,v,w; 116 scanf("%d%d%d",&u,&v,&w); 117 if (-1 == g[u][v] || g[u][v] > w) 118 g[u][v] = w; 119 } 120 kosaraju(); 121 build_map(); 122 scanf("%d",&k); 123 while (k--) 124 { 125 scanf("%d%d",&o,&d); 126 if (o == d || num[o] == num[d]) 127 printf("0\n"); 128 else 129 { 130 // 此处注意是num[o],num[d],因为是缩点后的图 131 dij(num[o],num[d]); 132 } 133 } 134 printf("\n"); 135 } 136 return 0; 137 }