题目链接:http://poj.org/problem?id=2186

题目大意:

每头牛都想成为牛群中的红人。

给定N头牛的牛群和M个有序对(A, B),(A, B)表示牛A认为牛B是红人;

该关系具有传递性,所以如果牛A认为牛B是红人,牛B认为牛C是红人,那么牛A也认为牛C是红人。

不过,给定的有序对中可能包含(A, B)和(B, C),但不包含(A, C)。

求被其他所有牛认为是红人的牛的总数。

题目分析(引自 https://www.cnblogs.com/violet-acmer/p/9740737.html):

考虑以牛为顶点的有向图,对每个有序对(A, B)连一条从 A到B的有向边;

那么,被其他所有牛认为是红人的牛对应的顶点,也就是从其他所有顶点都可达的顶点。

虽然这可以通过从每个顶点出发搜索求得,但总的复杂度却是O(NM),是不可行的,必须要考虑更为高效的算法。

假设有两头牛A和B都被其他所有牛认为是红人,那么显然,A被B认为是红人,B也被A认为是红人;

即存在一个包含A、B两个顶点的圈,或者说,A、B同属于一个强连通分量。

反之,如果一头牛被其他所有牛认为是红人,那么其所属的强连通分量内的所有牛都被其他所有牛认为是红人。

由此,我们把图进行强连通分量分解后,至多有一个强连通分量满足题目的条件。

而按前面介绍的算法进行强连通分量分解时,我们还能够得到各个强连通分量拓扑排序后的顺序;

唯一可能成为解的只有拓扑序最后的强连通分量。

所以在最后,我们只要检查这个强连通分量是否从所有顶点可达就好了。

思路整理:

1、首先,使用tarjan缩点;

2、其次,检查是否所有点可达

只需要确定是不是缩点后只有一个点的出度为0即可。

如果只有一个点的出度为0,则答案为该点对应的强连通分量中的原图中的点的数量;

否则,答案为 0。

实现代码如下:

#include <iostream>
#include <vector>
#include <stack>
#include <cstring>
using namespace std;
const int maxn = 10010;
int n, dfn[maxn], low[maxn], belong[maxn], idx, cnt;
bool instk[maxn];
stack<int> stk;
vector<int> g[maxn];
void tarjan(int u) {
dfn[u] = low[u] = ++idx;
instk[u] = true;
stk.push(u);
int sz = g[u].size();
for (int i = 0; i < sz; i ++) {
int v = g[u][i];
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (instk[v]) low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
cnt ++;
int v;
do {
v = stk.top();
stk.pop();
instk[v] = false;
belong[v] = cnt;
} while (u != v);
}
}
void solve() {
memset(dfn, 0, sizeof(dfn));
memset(instk, 0, sizeof(instk));
for (int i = 1; i <= n; i ++) if (!dfn[i]) tarjan(i);
}
int m;
bool vis[maxn];
int main() {
cin >> n >> m;
while (m --) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
}
solve();
for (int u = 1; u <= n; u ++) {
int sz = g[u].size();
for (int i = 0; i < sz; i ++) {
int v = g[u][i];
if (belong[u] != belong[v]) {
vis[ belong[u] ] = true;
}
}
}
int cc = 0, id = -1;
for (int i = 1; i <= cnt; i ++) if (!vis[i]) {
cc ++;
id = i;
}
if (cc != 1) {
cout << 0 << endl;
return 0;
}
int ans = 0;
for (int i = 1; i <= n; i ++) if (belong[i] == id) ans ++;
cout << ans << endl;
return 0;
}

POJ2186 Popular Cows 题解 强连通分量入门题的更多相关文章

  1. poj 2186 "Popular Cows"(强连通分量入门题)

    传送门 参考资料: [1]:挑战程序设计竞赛 题意: 每头牛都想成为牛群中的红人. 给定N头牛的牛群和M个有序对(A, B),(A, B)表示牛A认为牛B是红人: 该关系具有传递性,所以如果牛A认为牛 ...

  2. POJ2186 Popular Cows 题解 强连通分量

    题目链接:http://poj.org/problem?id=2186 题目大意: 每头牛都想成为牛群中的红人. 给定N头牛的牛群和M个有序对(A, B),(A, B)表示牛A认为牛B是红人: 该关系 ...

  3. POJ2186 Popular Cows 【强连通分量】+【Kosaraju】+【Tarjan】+【Garbow】

    Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 23445   Accepted: 9605 Des ...

  4. POJ2186 Popular Cows(强连通分量)

    题目问一个有向图所有点都能达到的点有几个. 先把图的强连通分量缩点,形成一个DAG,那么DAG“尾巴”(出度0的点)所表示的强连通分量就是解,因为前面的部分都能到达尾巴,但如果有多个尾巴那解就是0了, ...

  5. poj 2186 Popular Cows 【强连通分量Tarjan算法 + 树问题】

    题目地址:http://poj.org/problem?id=2186 Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Sub ...

  6. poj2186 Popular Cows 题解——S.B.S.

    Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 29642   Accepted: 11996 De ...

  7. POJ 2186 Popular Cows(强连通分量)

    [题目链接] http://poj.org/problem?id=2186 [题目大意] 给出一张有向图,问能被所有点到达的点的数量 [题解] 我们发现能成为答案的,只有拓扑序最后的SCC中的所有点, ...

  8. hdu1269强连通分量入门题

    https://vjudge.net/contest/156688#problem 为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<= ...

  9. POJ 2186 Popular Cows(强连通分量Kosaraju)

    http://poj.org/problem?id=2186 题意: 一个有向图,求出点的个数(任意点可达). 思路: Kosaraju算法的第一次dfs是后序遍历,而第二次遍历时遍历它的反向图,从标 ...

随机推荐

  1. CF 848C

    听说,一个好的oier是题目喂出来的. 题目 给定长度为n的数组, 定义数字X在[l,r]内的值为数字X在[l,r]内最后一次出现位置的下标减去第一次出现位置的下标 给定m次询问, 每次询问有三个整数 ...

  2. PHP 学习1.4

    1.session and cookie 示列: <?phpsession_start();?><!DOCTYPE html PUBLIC "-//W3C//DTD XHT ...

  3. Django与HTML业务基本结合--基本的用户名密码提交方法1

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. leetcode 21-30 easy

    21. Merge Two Sorted Lists Merge two sorted linked lists and return it as a new list. The new list s ...

  5. Codeforces 455C

    题目链接 C. Civilization time limit per test 1 second memory limit per test 256 megabytes input standard ...

  6. 【Leetcode 二分】 滑动窗口中位数(480)

    题目 中位数是有序序列最中间的那个数.如果序列的大小是偶数,则没有最中间的数:此时中位数是最中间的两个数的平均数. 例如: [2,3,4],中位数是 3 [2,3],中位数是 (2 + 3) / 2 ...

  7. PyCharm使用之利用Docker镜像搭建Python开发环境

      在我们平时使用PyCharm的过程中,一般都是连接本地的Python环境进行开发,但是如果是离线的环境呢?这样就不好搭建Python开发环境,因为第三方模块的依赖复杂,不好通过离线安装包的方式安装 ...

  8. R语言数据分析利器data.table包—数据框结构处理精讲

    R语言数据分析利器data.table包-数据框结构处理精讲 R语言data.table包是自带包data.frame的升级版,用于数据框格式数据的处理,最大的特点快.包括两个方面,一方面是写的快,代 ...

  9. iOS app发布流程

    http://www.xuebuyuan.com/1980497.html http://blog.csdn.net/alincexiaohao/article/details/38725367 ap ...

  10. BKDRHash算法的初步了解

    字符串hash最高效的算法,  搜了一下,  原理是: 字符串的字符集只有128个字符,所以把一个字符串当成128或更高进制的数字来看,当然是唯一的 这里unsigned不需要考虑溢出的问题,  不过 ...