做这题主要是为了学习一下tarjan的强连通分量,因为包括桥,双连通分量,强连通分量很多的求法其实都可以源于tarjan的这种方法,通过一个low,pre数组求出来。

题意:给你许多的A->B ,B->C这样的喜欢的关系,A->B ,B->C也意味着A->C,最后问你被全部别的人喜欢的cow有多少个。如果不告诉你用强连通分量,感觉可能会绕的远一些,但是如果知道了这个思路其实是很显然的。

首先是跑出每个强连通分量,在这种情况下,原来的图就变成了一棵树,一棵有有向边的树,然后不难发现,如果这棵树存在一个出度为0的点,那么它就很有可能是答案,为什么是可能呢?因为我们不知道是不是所有别的点都有路径连到它这里,所以判断的方法有这么几种吧。理论上如果只有1个出度为0的点应该就是答案了。还有一个是反向建图,然后从这个出度为0的点深搜,如果每个点都被搜到的话就说明这个点是可行的。

tarjan的算法大白书上有,具体不做过多的介绍,下面的代码有两种判断的,第一种简单,不用建图只需要统计出度,第二种复杂。在这道题了如果用Kosaraju算法会好过第二种,因为它搜出的强连通分量是按拓扑序的,tarjan则是不按的,所以用Kosaraju算法可以很容易求出那个出度为0的点。

#pragma warning(disable:4996)
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<stack>
#define maxn 10050
using namespace std; vector<int> G[maxn + 50];
int n, m; int out[maxn + 50];
int sccno[maxn + 50]; // 属于哪个强连通分量
int sccSize[maxn + 50];
int scc_cnt; // 强连通分量的数量 int pre[maxn + 50];
int low[maxn + 50];
int dfs_clock;
stack<int> S; int dfs(int u)
{
int lowu = pre[u] = ++dfs_clock;
S.push(u);
for (int i = 0; i < G[u].size(); i++){
int v = G[u][i];
if (!pre[v]){
int lowv = dfs(v);
lowu = min(lowu, lowv);
}
else if (!sccno[v]){
lowu = min(lowu, pre[v]);
}
}
if (lowu == pre[u]){
scc_cnt++;
while (1){
int x = S.top(); S.pop();
sccno[x] = scc_cnt;
sccSize[scc_cnt]++;
if (x == u) break;
}
}
return low[u] = lowu;
} void find_scc()
{
memset(sccno, 0, sizeof(sccno));
memset(pre, 0, sizeof(pre));
memset(sccSize, 0, sizeof(sccSize));
memset(low, 0, sizeof(low));
while (!S.empty()) S.pop();
dfs_clock = scc_cnt = 0;
for (int i = 1; i <= n; i++){
if (!pre[i]) dfs(i);
}
} vector<int> NG[maxn + 50]; void constructNG()
{
memset(out, 0, sizeof(out));
for (int i = 0; i <= scc_cnt; i++) NG[i].clear();
for (int i = 1; i <= n; i++){
for (int j = 0; j < G[i].size(); j++){
int u = i, v = G[i][j];
if (sccno[v] != sccno[u]){
out[sccno[u]]++;
NG[sccno[v]].push_back(sccno[u]);
}
}
}
} void ndfs(int u)
{
pre[u] = 1;
for (int i = 0; i < NG[u].size(); i++){
ndfs(NG[u][i]);
}
} int main()
{
while (cin >> n >> m)
{
for (int i = 0; i <= n; i++) G[i].clear();
int u, v;
for (int i = 0; i < m; i++){
scanf("%d%d", &u, &v);
G[u].push_back(v);
}
find_scc();
constructNG();
int foo = -1; int outnum = 0;
for (int i = 1; i <= scc_cnt; i++){
if (out[i] == 0){
foo = i; outnum++;
}
}
bool flag = true;
/*memset(pre, 0, sizeof(pre));
ndfs(foo);
bool flag = true;
for (int i = 1; i <= scc_cnt; i++){
if (!pre[i]){
flag = false; break;
}
}*/
if (outnum != 1) flag = false;
int ans = 0;
if (!flag) {
puts("0");
continue;
}
printf("%d\n", sccSize[foo]);
}
return 0;
}

POJ2186 Popular Cows 强连通分量tarjan的更多相关文章

  1. POJ2186 Popular Cows [强连通分量|缩点]

    Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 31241   Accepted: 12691 De ...

  2. poj 2186 Popular Cows (强连通分量+缩点)

    http://poj.org/problem?id=2186 Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissi ...

  3. POJ 2186 Popular Cows --强连通分量

    题意:给定一个有向图,问有多少个点由任意顶点出发都能达到. 分析:首先,在一个有向无环图中,能被所有点达到点,出度一定是0. 先求出所有的强连通分支,然后把每个强连通分支收缩成一个点,重新建图,这样, ...

  4. poj2186 Popular Cows --- 强连通

    给一个有向图,问有多少结点是其它全部结点都能够到达的. 等价于,在一个有向无环图上,找出度为0 的结点.假设出度为0的结点仅仅有一个,那么这个就是答案.假设大于1个.则答案是0. 这题有环.所以先缩点 ...

  5. POJ 2186 Popular Cows(强连通分量缩点)

    题目链接:http://poj.org/problem?id=2186 题目意思大概是:给定N(N<=10000)个点和M(M<=50000)条有向边,求有多少个“受欢迎的点”.所谓的“受 ...

  6. POJ 2186 Popular Cows 强连通分量模板

    题意 强连通分量,找独立的块 强连通分量裸题 #include <cstdio> #include <cstdlib> #include <cstring> #in ...

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

    这里的Tarjan是基于DFS,用于求有向图的强联通分量. 运用了一个点dfn时间戳和low的关系巧妙地判断出一个强联通分量,从而实现一次DFS即可求出所有的强联通分量. §有向图中, u可达v不一定 ...

  8. 洛谷——P2341 [HAOI2006]受欢迎的牛//POJ2186:Popular Cows

    P2341 [HAOI2006]受欢迎的牛/POJ2186:Popular Cows 题目背景 本题测试数据已修复. 题目描述 每头奶牛都梦想成为牛棚里的明星.被所有奶牛喜欢的奶牛就是一头明星奶牛.所 ...

  9. 强连通分量(tarjan求强连通分量)

    双DFS方法就是正dfs扫一遍,然后将边反向dfs扫一遍.<挑战程序设计>上有说明. 双dfs代码: #include <iostream> #include <cstd ...

随机推荐

  1. 安装MySQL软件

    安装MySQL软件(绿色版) ① 解压软件包 ② 更改文件夹名称为mysql并复制到/usr/local文件夹下 ③ 使用cd指令进入/usr/local/mysql文件夹,使用ls –l查看 查看后 ...

  2. SPA解释:单页应用程序

    单页Web应用(single page web application,SPA),就是只有一张Web页面的应用,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序. 单页W ...

  3. ARC小知识

    ARC是iOS 5推出的新功能,全称叫 ARC(Automatic Reference Counting).简单地说,就是代码中自动加入了retain/release,原先需要手动添加的用来处理内存管 ...

  4. 深入剖析——float之个人见解

    浮动的原本作用仅仅是为了实现文字的环绕效果. 以下分别是html与css代码,显示效果如下图.因为两个div使用了float浮动属性,所以脱离了标准文档流.让父元素撑开高度,我们需要清除浮动. < ...

  5. 浅谈 WPF控件

    首先我们必须知道在WPF中,控件通常被描述为和用户交互的元素,也就是能够接收焦点并响应键盘.鼠标输入的元素.我们可以把控件想象成一个容器,容器里装的东西就是它的内容.控件的内容可以是数据,也可以是控件 ...

  6. Storm集群安装详解

    storm有两种操作模式: 本地模式和远程模式. 本地模式:你可以在你的本地机器上开发测试你的topology, 一切都在你的本地机器上模拟出来; 远端模式:你提交的topology会在一个集群的机器 ...

  7. 含有自增序列的表中使用truncate与delete的不同结果

    一个含有自增序列的表,使用delete跟truncate之后会有什么不同结果呢? 大概说一下,使用truncate,表中的记录全部被清除,如果向表中插入数据,那么数据的排序是从1开始的. 如果使用的是 ...

  8. vim命令总结

    前言 本文翻译自:http://bencrowder.net/files/vim-fu/,参考了VIM中文帮助. Google翻译结果和实际操作结果,对原文的部分内容重新整理,删除和添加了 部分内容并 ...

  9. Entity Framework4.0 (六) EF4的 增加、删除、更改

    前面介绍了EF4的查询功能,主要是借助于LINQ的强大的查询功能和它简单的语法.让我们可以完全面向对象集体去进行查询,而不必去劳心处理那些关系型数据库表的操作.这样我们更容易把主要精力集中在业务逻辑上 ...

  10. Windows程序消息机制浅析

    1.消息  消息是由MSG结构体来表示的.如下: typedef struct tagMSG { HWND hwnd; UINT message; WPARAM wParam; LPARAM lPar ...