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 }

转载于:https://www.cnblogs.com/hujunzheng/p/3895221.html

poj2186Popular Cows(Kosaraju算法--有向图的强连通分量的分解)相关推荐

  1. C++Kosaraju找有向图的强连通分量算法(附完整源码)

    C++Kosaraju找有向图的强连通分量算法 C++Kosaraju找有向图的强连通分量算法完整源码(定义,实现,main函数测试) C++Kosaraju找有向图的强连通分量算法完整源码(定义,实 ...

  2. 有向图的强连通分量算法

    有向图的强连通分量算法 强连通分量定义 在有向图中,某个子集中的顶点可以直接或者间接互相可达,那么这个子集就是此有向图的一个强连通分量,值得注意的是,一旦某个节点划分为特定的强连通分量后,此顶点不能在 ...

  3. 算法提高课-图论-有向图的强连通分量-AcWing 367. 学校网络:强连通分量、tarjan算法

    文章目录 题目解答 题目来源 题目解答 来源:acwing 分析: 第一问:通过tarjan算法求出强连通分量并且缩点后,统计入度为0的点的个数p即可. 第二问,至少加几条边才能使图变成强连通分量?这 ...

  4. 算法提高课-图论-有向图的强连通分量-AcWing 1174. 受欢迎的牛:tarjan算法求强连通分量、tarjan算法板子、强连通图

    文章目录 题目解答 题目来源 题目解答 来源:acwing 分析: 强连通图:给定一张有向图.若对于图中任意两个结点x,y,既存在从x到y的路径,也存在从y到x的路径,则称该有向图是"强连通 ...

  5. 有向图的强连通分量,割点与桥

    有向图的强连通分量 1.Tarjan /* Tarjan算法 复杂度O(N+M) */ #include<iostream> #include<stdio.h> #includ ...

  6. Tarjan 求有向图的强连通分量

    Tarjan 算法与有向图的连通性 Tarjan 算法是基于对图进行深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树.搜索时,把当前搜索树中未处理的节点加入一个栈,回溯时可以判断栈顶到栈中的节点 ...

  7. 缩点(有向图的强连通分量)学习笔记

    缩点(有向图的强连通分量)学习笔记 1.什么是强连通分量?: 有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路 ...

  8. 【UOJ 92】有向图的强连通分量

    [题目描述]: 有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly co ...

  9. 有向图的强连通分量(SCC)

    有向图的强连通分量(SCC) 1. 有向图的强连通分量原理 原理 强连通分量是针对有向图来说的.如下的讲解默认都是针对有向图的. 连通分量:对于一个有向图中的一些点来说,如果任意两点都能相互到达,则称 ...

最新文章

  1. PyTorch Data Parrallel数据并行
  2. vue = 什么意思_Vue 00 —— 初识 Vue,从放弃到入门
  3. GDI+ 获取本地电脑的图片编码器
  4. ShaderLab学习小结(十九)RenderToCubemap创建能反射周围环境的效果
  5. MySql轻松入门系列——第一站 从源码角度轻松认识mysql整体框架图
  6. Infinite Fraction Path UVALive - 8207
  7. Python3.6 IDLE 使用 multiprocessing.Process 不显示执行函数的打印
  8. android 日历 课程设计,课程设计-数字日历的设计
  9. Xcode XIB中突然变卡顿的原因
  10. pandas 下一行减去上一行
  11. 关于linux无法联网以及xshell无法连接linux的解决
  12. VS2015编译程序兼容XP
  13. oa系统服务器地址怎么查找,oa系统的服务器地址怎么看
  14. mysql和JDBC学习
  15. vs2010调试c语言找不到exe文件夹,vs上调试和直接运行exe不同
  16. oracle 恢复删除的数据 oracle恢复删除的数据
  17. mvn compile报错“程序包com.XXX不存在”
  18. Java字符串转时间
  19. mt6735通用recovery_Mtk arm64通用root ,使用无需bl或者rec,安卓7以下使用最佳!
  20. python文字识别前端_Python文字识别

热门文章

  1. axis2 默认端口_基于 AXIS2/C 的 C 语言库实现对提供 REST API 的系统进行数据访问...
  2. docker-compose 实战案例
  3. Springboot2.x +JPA 集成 Apache ShardingSphere 同库分表
  4. IntelliJ IDEA 2020.1 瞬间定位文件夹、文件
  5. 正则表达式中的开头和结尾
  6. 软件设计师 -主观题总结
  7. 适用于ios和android,适用于iOS和Android的OpenGL ES差异
  8. Leetcode 242.有效的字母异位词(哈希表)
  9. Linux大作业任务书,《Linux系统管理》期末大作业任务书(2014.12)(1).doc
  10. android选择多个文件_一分钟合并多个Excel、PDF文件,3种方法任你选择,好用到没朋友...