POJ2186(强连通分量分解)

Popular Cows

Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 35035   Accepted: 14278

Description

Every cow‘s dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is 
popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow.

Input

* Line 1: Two space-separated integers, N and M

* Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.

Output

* Line 1: A single integer that is the number of cows who are considered popular by every other cow.

Sample Input

3 3
1 2
2 1
2 3

Sample Output

1

Hint

Cow 3 is the only cow of high popularity.

Source

USACO 2003 Fall

题意:求从其他所有顶点都可以到达的顶点数目。

思路:所求顶点数目即为拓扑序最后的强连通分量中的顶点数目,检查其他点是否都可以到达该强连通分量。

  1 //2017-08-20
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 #include <algorithm>
  6 #include <vector>
  7
  8 using namespace std;
  9
 10 const int N = 10010;
 11 vector<int> G[N];//邻接表存图
 12 vector<int> rG[N];//存反向图
 13 vector<int> vs;//后序遍历顺序的顶点列表
 14 bool vis[N];
 15 int cmp[N];//所属强连通分量的拓扑序
 16
 17 void add_edge(int u, int v){
 18     G[u].push_back(v);
 19     rG[v].push_back(u);
 20 }
 21
 22 //input: u 顶点
 23 //output: vs 后序遍历顺序的顶点列表
 24 void dfs(int u){
 25     vis[u] = true;
 26     for(int i = 0; i < G[u].size(); i++){
 27         int v = G[u][i];
 28         if(!vis[v])
 29               dfs(v);
 30     }
 31     vs.push_back(u);
 32 }
 33
 34 //input: u 顶点编号; k 拓扑序号
 35 //output: cmp[] 强连通分量拓扑序
 36 void rdfs(int u, int k){
 37     vis[u] = true;
 38     cmp[u] = k;
 39     for(int i = 0; i < rG[u].size(); i++){
 40         int v = rG[u][i];
 41         if(!vis[v])
 42               rdfs(v, k);
 43     }
 44 }
 45
 46 //Strongly Connected Component 强连通分量
 47 //input: n 顶点个数
 48 //output: k 强连通分量数;
 49 int scc(int n){
 50     memset(vis, 0, sizeof(vis));
 51     vs.clear();
 52     for(int u = 0; u < n; u++)
 53         if(!vis[u])
 54               dfs(u);
 55     int k = 0;
 56     memset(vis, 0, sizeof(vis));
 57     for(int i = vs.size()-1; i >= 0; i--)
 58           if(!vis[vs[i]])
 59               rdfs(vs[i], k++);
 60     return k;
 61 }
 62
 63 void solve(int n){
 64     int k = scc(n);
 65     int u = 0, ans = 0;
 66     for(int v = 0; v < n; v++){
 67         if(cmp[v] == k-1){
 68             u = v;
 69             ans++;
 70         }
 71     }
 72     memset(vis, 0, sizeof(vis));
 73     rdfs(u, 0);
 74     for(int i = 0; i < n; i++){
 75         if(!vis[i]){
 76             ans = 0;
 77             break;
 78         }
 79     }
 80     printf("%d\n", ans);
 81 }
 82
 83 int main()
 84 {
 85     int n, m;
 86     while(scanf("%d%d", &n, &m)!=EOF){
 87         int u, v;
 88         for(int i = 0; i < n; i++){
 89             G[i].clear();
 90             rG[i].clear();
 91         }
 92         while(m--){
 93             scanf("%d%d", &u, &v);
 94             u--; v--;
 95             add_edge(u, v);
 96         }
 97         solve(n);
 98     }
 99
100     return 0;
101 }
时间: 2024-10-21 05:59:24

POJ2186(强连通分量分解)的相关文章

【强连通分量分解】

摘自<挑战程序设计>4.3.1 [强连通分量分解原理] 对于一个有向图顶点的子集S,如果在S内任取两个顶点u和v,都能找到一条从u到v的路径,那么就称S是强连通的.如果在强连通的顶点集合S中加入其他任意顶点集合后,它都不再是强连通的,那么就称S是原图的一个强连通分量(SCC: Strongly Connected Component).任意有向图都可以分解成若干不相交的强连通分量,这就是强连通分量分解.把分解后的强连通分量缩成一个顶点,就得到了一个DAG(有向无环图). 强连通分量分解可以通过

强连通分量分解 tarjan算法 (hdu 1269)

题意: 给出一个有n个点m条边的有向图,判断该图是否只有一个强连通分量. 限制: 0 <= N <= 10000 0 <= M <= 100000 思路: tarjan算法分解强连通分量. /*强连通分量分解 tarjan算法 (hdu 1269) 题意: 给出一个有n个点m条边的有向图,判断该图是否只有一个强连通分量. 限制: 0 <= N <= 10000 0 <= M <= 100000 */ #include<iostream> #inc

POJ(2186)强连通分量分解

#include<cstdio> #include<vector> #include<cstring> using namespace std; const int MAX_N=10005; vector<int> G[MAX_N]; vector<int> rG[MAX_N];//存储边反向之后的图 vector<int> PostOrder;//存储图的后序遍历 int V,E; bool used[MAX_N]; int com

强连通分量分解

#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; const int N = 10000 + 10; const int M = 50000 + 10; int n, m; int head1[N], tot1, head2[N], tot2; bool vis[N

强连通分量分解 Kosaraju算法 (poj 2186 Popular Cows)

poj 2186 Popular Cows 题意: 有N头牛, 给出M对关系, 如(1,2)代表1欢迎2, 关系是单向的且可以传递, 即1欢迎2不代表2欢迎1, 但是如果2也欢迎3那么1也欢迎3. 求被所有牛都欢迎的牛的数量. 限制: 1 <= N <= 10000 1 <= M <= 50000 思路: Kosaraju算法, 看缩点后拓扑序的终点有多少头牛, 且要判断是不是所有强连通分量都连向它. Kosaraju算法,分拆完连通分量后,也完成了拓扑序. /*poj 2186

poj2186 强连通分量 targan算法的应用

这个题的意思是给你一些牛和一些边, 假设A 膜拜 B, B膜拜C, 那么A就膜拜C, 然后让你求被其他所有的牛都膜拜的牛的个数, 使用targan算法缩点, 将图变成有向无环图DAG 之后统计顶点的入度, 假设顶点入度为0的个数超过了1, 那么答案是0, 否则输出这个集合的牛的数量. 代码如下: #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using

强连通分量tarjan模板复习

对于一个有向图定点的子集,在该子集中任取两点u与v,都能找到一条从u到v的路径,则称该子集是强连通的.若该集合加入到任意点集中,它都不再强连通,则称这个子集是原图的一个强连通分量.任意一张图都可以分解成若干个不相交的强连通分量.这是强连通分量分解.把分解后的强连通分量缩成一个顶点,就可以得到一个有向无环图. 如图: 求一张图的强连通分量的个数,常用tarjan算法,它是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树.搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈

强连通分量+poj2186

强连通分量:两个点能够互相连通. 算法分解:第一步.正向dfs全部顶点,并后序遍历 第二步,将边反向,从最大边dfs,构成强连通分量 标号最大的节点属于DAG头部,cmp存一个强连通分量的拓扑序. poj2186 解就是拓扑后的最后一个强连通分量 #include<cstdio> #include<algorithm> #include<vector> #include<iostream> #include<cstring> #include&l

强连通分量tarjan缩点——POJ2186 Popular Cows

这里的Tarjan是基于DFS,用于求有向图的强联通分量. 运用了一个点dfn时间戳和low的关系巧妙地判断出一个强联通分量,从而实现一次DFS即可求出所有的强联通分量. §有向图中, u可达v不一定意味着v可达u.    相互可达则属于同一个强连通分量    (Strongly Connected Component, SCC) §有向图和它的转置的强连通分量相同 §所有SCC构成一个DAG(有向无环图) dfn[u]为节点u搜索的次序编号(时间戳),即首次访问u的时间 low[u]为u或u的