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 }

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

时间: 2024-12-28 21:06:58

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

『Tarjan算法 有向图的强连通分量』

有向图的强连通分量 定义:在有向图\(G\)中,如果两个顶点\(v_i,v_j\)间\((v_i>v_j)\)有一条从\(v_i\)到\(v_j\)的有向路径,同时还有一条从\(v_j\)到\(v_i\)的有向路径,则称两个顶点强连通(strongly connected).如果有向图\(G\)的每两个顶点都强连通,称\(G\)是一个强连通图.有向图的极大强连通子图,称为强连通分量(strongly connected components). 万能的Tarjan算法也可以帮助我们求解有向图的强

有向图的强连通分量(tarjan算法)

强连通分量 有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.有向图的极大强连通子图,称为强连通分量(strongly connected components). 考虑强连通分量C,设其中第一个被发现的点为x,则,C中其他的点都是x的后代.我们希望在x访问完成时立即输出C(可以同时记录C,输出代表

hdu1269 迷宫城堡,有向图的强连通分量 , Tarjan算法

hdu1269 迷宫城堡 验证给出的有向图是不是强连通图... Tarjan算法板子题 Tarjan算法的基础是DFS,对于每个节点.每条边都搜索一次,时间复杂度为O(V+E). 算法步骤: 1.搜索到某一个点时,将该点的Low值标上时间戳,然后将自己作为所在强连通分量的根节点(就是赋值Dfn=Low=time) 2.将该点压入栈. 3.当点p有与点p'相连时,如果此时p'不在栈中,p的low值为两点的low值中较小的一个. 4.当点p有与点p'相连时,如果此时p'在栈中,p的low值为p的lo

求有向图的强连通分量的算法

下面是求有向图的强连通分量的算法的代码: import java.util.Scanner; class Qiufenliang//定义求强连通分量的类 { String lu="";//定义的一个字符型变量,记录强连通分量的路径 public static int s=0; public void qiu(int a[][],int l)//定义函数,参数a为二维数组,参数l为数组的维数 { int t=0;//定义int型变量,进行数量的统计 for(int i=1;i<l;

UVA247- Calling Circles(有向图的强连通分量)

题目链接 题意: 给定一张有向图,找出所有强连通分量,并输出. 思路:有向图的强连通分量用Tarjan算法,然后用map映射,便于输出,注意输出格式. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <map> #include <algorithm> using namespace std; const int MAXN = 2000; const in

图-&gt;连通性-&gt;有向图的强连通分量

文字描述 有向图强连通分量的定义:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.有向图的极大强连通子图,称为强连通分量(strongly connected components). 用深度优先搜索求有向图的强连通分量的方法如下并假设有向图的存储结构为十字链表. 1 在有向图G上,从某个定点出发沿以该顶点为尾的弧

连通分量 无向图的割顶和桥 无向图的双连通分量 有向图的强连通分量

时间戳 dfs_clock :说白了就是记录下访问每个结点的次序.假设我们用 pre 保存,那么如果 pre[u] > pre[v], 那么就可以知道先访问的 v ,后访问的 u . 现在给定一条边, (u, v), 且 u 的祖先为 fa, 如果有 pre[v] < pre[u] && v != fa, 那么 (u, v) 为一条反向边. 1 求连通分量: 相互可达的节点称为一个连通分量: #include <iostream> #include <cstd

uva11324 有向图的强连通分量+记忆化dp

给一张有向图G, 求一个结点数最大的结点集,使得该结点集中任意两个结点u和v满足,要么u可以到达v, 要么v可以到达u(u和v相互可达也可以). 因为整张图可能存在环路,所以不好使用dp直接做,先采用有向图的强连通分量,进行缩点,然后得到一个有向无环图(DAG) 在采用记忆话dp 去做即可 #include <iostream> #include <cstdio> #include <algorithm> #include <string.h> #inclu

DFS的运用(二分图判定、无向图的割顶和桥,双连通分量,有向图的强连通分量)

一.dfs框架: 1 vector<int>G[maxn]; //存图 2 int vis[maxn]; //节点访问标记 3 void dfs(int u) 4 { 5 vis[u] = 1; 6 PREVISIT(u); //访问节点u之前的操作 7 int d = G[u].size(); 8 for(int i = 0; i < d; i++)//枚举每条边 9 { 10 int v = G[u][i]; 11 if(!vis[v])dfs(v); 12 } 13 POSTVIS