poj2186Popular Cows(Kosaraju算法--有向图的强连通分量的分解)
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算法--有向图的强连通分量的分解)相关推荐
- C++Kosaraju找有向图的强连通分量算法(附完整源码)
C++Kosaraju找有向图的强连通分量算法 C++Kosaraju找有向图的强连通分量算法完整源码(定义,实现,main函数测试) C++Kosaraju找有向图的强连通分量算法完整源码(定义,实 ...
- 有向图的强连通分量算法
有向图的强连通分量算法 强连通分量定义 在有向图中,某个子集中的顶点可以直接或者间接互相可达,那么这个子集就是此有向图的一个强连通分量,值得注意的是,一旦某个节点划分为特定的强连通分量后,此顶点不能在 ...
- 算法提高课-图论-有向图的强连通分量-AcWing 367. 学校网络:强连通分量、tarjan算法
文章目录 题目解答 题目来源 题目解答 来源:acwing 分析: 第一问:通过tarjan算法求出强连通分量并且缩点后,统计入度为0的点的个数p即可. 第二问,至少加几条边才能使图变成强连通分量?这 ...
- 算法提高课-图论-有向图的强连通分量-AcWing 1174. 受欢迎的牛:tarjan算法求强连通分量、tarjan算法板子、强连通图
文章目录 题目解答 题目来源 题目解答 来源:acwing 分析: 强连通图:给定一张有向图.若对于图中任意两个结点x,y,既存在从x到y的路径,也存在从y到x的路径,则称该有向图是"强连通 ...
- 有向图的强连通分量,割点与桥
有向图的强连通分量 1.Tarjan /* Tarjan算法 复杂度O(N+M) */ #include<iostream> #include<stdio.h> #includ ...
- Tarjan 求有向图的强连通分量
Tarjan 算法与有向图的连通性 Tarjan 算法是基于对图进行深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树.搜索时,把当前搜索树中未处理的节点加入一个栈,回溯时可以判断栈顶到栈中的节点 ...
- 缩点(有向图的强连通分量)学习笔记
缩点(有向图的强连通分量)学习笔记 1.什么是强连通分量?: 有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路 ...
- 【UOJ 92】有向图的强连通分量
[题目描述]: 有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly co ...
- 有向图的强连通分量(SCC)
有向图的强连通分量(SCC) 1. 有向图的强连通分量原理 原理 强连通分量是针对有向图来说的.如下的讲解默认都是针对有向图的. 连通分量:对于一个有向图中的一些点来说,如果任意两点都能相互到达,则称 ...
最新文章
- PyTorch Data Parrallel数据并行
- vue = 什么意思_Vue 00 —— 初识 Vue,从放弃到入门
- GDI+ 获取本地电脑的图片编码器
- ShaderLab学习小结(十九)RenderToCubemap创建能反射周围环境的效果
- MySql轻松入门系列——第一站 从源码角度轻松认识mysql整体框架图
- Infinite Fraction Path UVALive - 8207
- Python3.6 IDLE 使用 multiprocessing.Process 不显示执行函数的打印
- android 日历 课程设计,课程设计-数字日历的设计
- Xcode XIB中突然变卡顿的原因
- pandas 下一行减去上一行
- 关于linux无法联网以及xshell无法连接linux的解决
- VS2015编译程序兼容XP
- oa系统服务器地址怎么查找,oa系统的服务器地址怎么看
- mysql和JDBC学习
- vs2010调试c语言找不到exe文件夹,vs上调试和直接运行exe不同
- oracle 恢复删除的数据 oracle恢复删除的数据
- mvn compile报错“程序包com.XXX不存在”
- Java字符串转时间
- mt6735通用recovery_Mtk arm64通用root ,使用无需bl或者rec,安卓7以下使用最佳!
- python文字识别前端_Python文字识别
热门文章
- axis2 默认端口_基于 AXIS2/C 的 C 语言库实现对提供 REST API 的系统进行数据访问...
- docker-compose 实战案例
- Springboot2.x +JPA 集成 Apache ShardingSphere 同库分表
- IntelliJ IDEA 2020.1 瞬间定位文件夹、文件
- 正则表达式中的开头和结尾
- 软件设计师 -主观题总结
- 适用于ios和android,适用于iOS和Android的OpenGL ES差异
- Leetcode 242.有效的字母异位词(哈希表)
- Linux大作业任务书,《Linux系统管理》期末大作业任务书(2014.12)(1).doc
- android选择多个文件_一分钟合并多个Excel、PDF文件,3种方法任你选择,好用到没朋友...