标签:连通 cst main names std cto 有向图 mem set
题意:
给定一个有向图,求有多少个顶点是由任何顶点出发都可达的。
顶点数<= 10,000,边数 <= 50,000
思路:
Korasaju算法把图进行强连通分量分解,在分解的同时得到各个强连通分量拓扑序。唯一可能成为解的就是拓扑序最后的强连通分量,最后再检查这个强连通分量是否能从各个顶点均可达即可。
实现:
1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <cstring> 5 using namespace std; 6 7 vector<int> G[10005], G_t[10005], res; 8 int n, m, x, y, cmp[10005]; 9 bool vis[10005]; 10 void dfs(int x) 11 { 12 vis[x] = true; 13 for (int i = 0; i < G[x].size(); i++) 14 { 15 if (!vis[G[x][i]]) 16 dfs(G[x][i]); 17 } 18 res.push_back(x); 19 } 20 21 void rdfs(int x, int k) 22 { 23 vis[x] = true; 24 cmp[x] = k; 25 for (int i = 0; i < G_t[x].size(); i++) 26 { 27 if (!vis[G_t[x][i]]) 28 { 29 rdfs(G_t[x][i], k); 30 } 31 } 32 } 33 34 int main() 35 { 36 while (cin >> n >> m) 37 { 38 for (int i = 1; i <= n; i++) 39 { 40 G[i].clear(); 41 G_t[i].clear(); 42 } 43 res.clear(); 44 for (int i = 0; i < m; i++) 45 { 46 scanf("%d %d", &x, &y); 47 G[x].push_back(y); 48 G_t[y].push_back(x); 49 } 50 memset(vis, 0, sizeof(vis)); 51 for (int i = 1; i <= n; i++) 52 { 53 if (!vis[i]) 54 dfs(i); 55 } 56 memset(vis, 0, sizeof(vis)); 57 int k = 0; 58 for (int i = res.size() - 1; i >= 0; i--) 59 { 60 if (!vis[res[i]]) 61 { 62 rdfs(res[i], k++); 63 } 64 } 65 int cnt = 0, tmp = 0; 66 for (int i = 1; i <= n; i++) 67 { 68 if (cmp[i] == k - 1) 69 { 70 cnt++; 71 tmp = i; 72 } 73 } 74 memset(vis, 0, sizeof(vis)); 75 rdfs(tmp, 0); 76 for (int i = 1; i <= n; i++) 77 { 78 if (!vis[i]) 79 { 80 cnt = 0; 81 break; 82 } 83 } 84 printf("%d\n", cnt); 85 } 86 return 0; 87 }
总结:
有向图进行进行强连通分量分解并缩点之后可以得到一个DAG。
如果有多于一个出度为0的缩点则解为0。
标签:连通 cst main names std cto 有向图 mem set
原文地址:http://www.cnblogs.com/wangyiming/p/6357988.html