1 /* 2 题目大意:有N个cows, M个关系 3 a->b 表示 a认为b popular;如果还有b->c, 那么就会有a->c 4 问最终有多少个cows被其他所有cows认为是popular! 5 6 思路:强连通分量中每两个节点都是可达的! 通过分解得到最后一个连通分量A, 7 如果将所有的强连通分量看成一个大的节点,那么A一定是孩子节点(因为我们先 8 完成的是父亲节点的强连通分量)! 最后如果其他的强连通分量都可以指向A,那么 9 A中的每一个cow都会被其他cows所有的cows认为popular! 10 */ 11 #include <string> 12 #include <cstdio> 13 #include <cstring> 14 #include <iostream> 15 #include<vector> 16 #define M 10005 17 using namespace std; 18 19 vector<int>ex[M]; 20 vector<int>ey[M]; 21 22 int n, m; 23 int cnt[M];//记录第一次dfs的节点的逆序 24 int vis[M];//标记节点是否已经被访问过了 25 int mark[M];//标记每一个节点是属于哪一个连通分量 26 int ans; 27 int top; 28 29 void dfs1(int u){//出度遍历 30 if(!vis[u]){ 31 vis[u]=1; 32 int len=ex[u].size(); 33 for(int i=0; i<len; ++i){ 34 int v=ex[u][i]; 35 dfs1(v); 36 } 37 cnt[top++]=u; 38 } 39 } 40 41 void dfs2(int u){//入度遍历 42 if(!vis[u]){ 43 vis[u]=1; 44 mark[u]=ans; 45 int len=ey[u].size(); 46 for(int i=0; i<len; ++i){ 47 int v=ey[u][i]; 48 dfs2(v); 49 } 50 } 51 } 52 53 int main(){ 54 while(scanf("%d%d", &n, &m)!=EOF){ 55 while(m--){ 56 int u, v; 57 scanf("%d%d", &u, &v); 58 ex[u].push_back(v); 59 ey[v].push_back(u); 60 } 61 ans=top=0; 62 for(int i=1; i<=n; ++i) 63 if(!vis[i]) 64 dfs1(i); 65 66 memset(vis, 0, sizeof(vis)); 67 68 for(int i=top-1; i>=0; --i) 69 if(!vis[cnt[i]]){ 70 ++ans; 71 dfs2(cnt[i]); 72 } 73 int count=0; 74 int u=0; 75 for(int i=1; i<=n; ++i) 76 if(mark[i]==ans){ 77 ++count; 78 u=i; 79 } 80 memset(vis, 0, sizeof(vis)); 81 dfs2(u); 82 83 for(int i=1; i<=n; ++i)//其他的强连通分量是否都指向了最后一个强连通分量 84 if(!vis[i]){ 85 count=0; 86 break; 87 } 88 printf("%d\n", count); 89 for(int i=1; i<=n; ++i){ 90 ex[i].clear(); 91 ey[i].clear(); 92 } 93 memset(vis, 0, sizeof(vis)); 94 } 95 return 0; 96 }
1 /* 2 tarjan 算法果然nb! 首先我们利用该算法将所有的强连通分量分开! 3 然后将每一个连通分量看成是一个点,这样就成了一个有向无环图! 4 接着判断初度为 0 的点一共有多少个!如果只有一个,那么最终的答案就是 5 这个节点终所有子节点的个数!也就是说这个节点中的每一个子节点都能 6 其他的所有节点到达! 7 8 如果初度为 0 的点多余1个,那么对不起,不能满足某个节点恰好能被其他所有 9 的节点访问到! 10 */#include<iostream> 11 #include<cstdio> 12 #include<vector> 13 #include<stack> 14 #include<cstring> 15 #define M 10005 16 using namespace std; 17 18 vector<int>edge[M]; 19 stack<int>s; 20 int low[M], vis[M]; 21 int sccN[M], pre[M]; 22 int n, m; 23 int dfs_clock, cnt; 24 25 void dfs(int u){//tarjan 算法 26 int len = edge[u].size(); 27 pre[u]=low[u]=++dfs_clock; 28 s.push(u); 29 for(int i=0; i<len; ++i){ 30 int v=edge[u][i]; 31 if(!pre[v]){ 32 dfs(v); 33 low[u]=min(low[u], low[v]); 34 } 35 else if(!sccN[v]) 36 low[u] = min(low[u], pre[v]); 37 } 38 if(low[u]==pre[u]){ 39 ++cnt; 40 while(1){ 41 int v=s.top(); 42 s.pop(); 43 sccN[v]=cnt; 44 if(u==v) break; 45 } 46 } 47 } 48 49 int main(){ 50 while(scanf("%d%d", &n, &m)!=EOF){ 51 dfs_clock=cnt=0; 52 memset(pre, 0, sizeof(pre)); 53 memset(sccN, 0, sizeof(sccN)); 54 memset(vis, 0, sizeof(vis)); 55 while(m--){ 56 int u, v; 57 scanf("%d%d", &u, &v); 58 edge[u].push_back(v); 59 } 60 for(int i=1; i<=n; ++i) 61 if(!pre[i]) 62 dfs(i); 63 int num=0; 64 for(int i=1; i<=n; ++i) 65 if(sccN[i]==1) 66 ++num; 67 int count=0; 68 memset(vis, 0, sizeof(vis)); 69 for(int i=1; i<=n; ++i){ 70 int len=edge[i].size(); 71 for(int j=0; j<len; ++j) 72 if(sccN[i] != sccN[edge[i][j]]){ 73 vis[sccN[i]]=1; 74 break; 75 } 76 } 77 78 for(int i=1; i<=cnt; ++i) 79 if(!vis[i]) ++count; 80 if(count==1) 81 printf("%d\n", num); 82 else printf("0\n"); 83 for(int i=1; i<=n; ++i) 84 edge[i].clear(); 85 while(!s.empty()) 86 s.pop(); 87 } 88 return 0; 89 }
1 /*比较慢的方法就是:利用tarjan算法将所有的强连通分量进行分离之后, 2 将每一个强连通分量看成是一个点,如果有满足我们答案的解,那么初度为零 3 点一定只有一个,并且这个点的所有子节点的编号是 1!那么我们先计算出子节点 4 编号为 1的个数, 然后在判断其他的强连通分量的节点是否能够到达编号为 1 的 5 强连通分量! */ 6 #include<iostream> 7 #include<cstdio> 8 #include<vector> 9 #include<stack> 10 #include<cstring> 11 #define M 10005 12 using namespace std; 13 14 vector<int>edge[M]; 15 stack<int>s; 16 int low[M], vis[M], used[M]; 17 int sccN[M], pre[M]; 18 int n, m; 19 int dfs_clock, cnt, sum, xx; 20 21 void dfs(int u){ 22 int len = edge[u].size(); 23 pre[u]=low[u]=++dfs_clock; 24 s.push(u); 25 for(int i=0; i<len; ++i){ 26 int v=edge[u][i]; 27 if(!pre[v]){ 28 dfs(v); 29 low[u]=min(low[u], low[v]); 30 } 31 else if(!sccN[v]) 32 low[u] = min(low[u], pre[v]); 33 } 34 if(low[u]==pre[u]){ 35 ++cnt; 36 while(1){ 37 int v=s.top(); 38 s.pop(); 39 sccN[v]=cnt; 40 if(u==v) break; 41 } 42 } 43 } 44 45 int dfs2(int u){ 46 int len=edge[u].size(); 47 if(sccN[u]==1){//到达之后就不在进行任何搜索 48 sum+=xx; 49 return 1; 50 } 51 vis[u]=1; 52 for(int i=0; i<len; ++i){ 53 int v=edge[u][i]; 54 if(!vis[v]){ 55 if(dfs2(v)) 56 return 1; 57 } 58 } 59 return 0; 60 } 61 62 int main(){ 63 while(scanf("%d%d", &n, &m)!=EOF){ 64 dfs_clock=cnt=0; 65 memset(pre, 0, sizeof(pre)); 66 memset(sccN, 0, sizeof(sccN)); 67 memset(vis, 0, sizeof(vis)); 68 memset(used, 0, sizeof(used)); 69 while(m--){ 70 int u, v; 71 scanf("%d%d", &u, &v); 72 edge[u].push_back(v); 73 } 74 for(int i=1; i<=n; ++i) 75 if(!pre[i]) 76 dfs(i); 77 int num=0; 78 sum=0; 79 used[1]=1; 80 for(int i=1; i<=n; ++i){ 81 82 if(sccN[i]==1) 83 ++num; 84 else if(!used[sccN[i]]){ 85 memset(vis, 0, sizeof(vis)); 86 xx=sccN[i]; 87 used[sccN[i]]=1; 88 dfs2(i); 89 } 90 } 91 92 if(sum==(cnt+1)*cnt/2-1)//最后将能到达标号为1的连通分量的所有强连通分量的标号加起来 93 printf("%d\n", num); 94 else printf("0\n"); 95 for(int i=1; i<=n; ++i) 96 edge[i].clear(); 97 while(!s.empty()) 98 s.pop(); 99 } 100 return 0; 101 }