传送门

参考资料:

  [1]:挑战程序设计竞赛

题意:

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

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

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

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

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

分析(摘抄自挑战程序设计竞赛):

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

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

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

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

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

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

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

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

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

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

  该算法的复杂度为O(N+M),足以在时限内解决原题。

对红色字体的理解:

  满足条件的强连通分量的特点是(红牛所在的强连通分量):

    (1)出度为0

    (2)其余的节点都会间接或直接的指向此强连通分量的任一节点

  再结合向量vs 的作用,在Dfs( )中,vs中存储的第一个节点肯定是满足条件的强连通分量中的某一节点;

  在vs中,越靠前的节点的拓扑序越大。

AC代码:

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn=1e5+; int n,m;
int num;
int head[maxn];
struct Edge
{
int to;
int next;
}G[*maxn];
void addEdge(int u,int v)
{
G[num]={v,head[u]};
head[u]=num++;
}
struct SCC
{
int col[maxn];
bool vis[maxn];
vector<int >vs;
void DFS(int u)
{
vis[u]=true;
for(int i=head[u];~i;i=G[i].next)
{
int v=G[i].to;
if((i&) || vis[v])//正向边,num为偶数
continue;
DFS(v);
}
vs.push_back(u);
}
void RDFS(int u,int k)
{
vis[u]=true;
col[u]=k;
for(int i=head[u];~i;i=G[i].next)
{
int v=G[i].to;
if(!(i&) || vis[v])//反向边,num为奇数
continue;
RDFS(v,k);
}
}
int scc()
{
vs.clear();
mem(vis,false);
for(int i=;i <= n;++i)
if(!vis[i])
DFS(i); int k=;
mem(vis,false);
for(int i=vs.size()-;i >= ;--i)//从拓扑序的最大值开始查找SCC
if(!vis[vs[i]])
RDFS(vs[i],++k);
return k;
}
}_scc;
int Solve()
{
int k=_scc.scc();
int ans=;
int u;
for(int i=;i <= n;++i)
if(_scc.col[i] == k)
{
ans++;
u=i;
}
mem(_scc.vis,false);
_scc.RDFS(u,);//再次调用RDFS()判断u是否可以到达其他任意节点
for(int i=;i <= n;++i)
if(!_scc.vis[i])
return ;
return ans;
}
void Init()
{
num=;
mem(head,-);
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
Init();
for(int i=;i <= m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
addEdge(u,v);
addEdge(v,u);
}
printf("%d\n",Solve());
}
return ;
}

poj 2186 "Popular Cows"(强连通分量入门题)的更多相关文章

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

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

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

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

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

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

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

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

  5. poj 2186: Popular Cows(tarjan基础题)

    题目链接 tarjan参考博客 题意:求在图上可以被所有点到达的点的数量. 首先通过tarjan缩点,将所有内部两两可达的子图缩为一点,新图即为一个有向无环图(即DAG). 在这个DAG上,若存在不止 ...

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

    poj 2186 Popular Cows 题意: 有N头牛, 给出M对关系, 如(1,2)代表1欢迎2, 关系是单向的且能够传递, 即1欢迎2不代表2欢迎1, 可是假设2也欢迎3那么1也欢迎3. 求 ...

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

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

  8. POJ 2186 Popular Cows (强联通)

    id=2186">http://poj.org/problem? id=2186 Popular Cows Time Limit: 2000MS   Memory Limit: 655 ...

  9. tarjan缩点练习 洛谷P3387 【模板】缩点+poj 2186 Popular Cows

    缩点练习 洛谷 P3387 [模板]缩点 缩点 解题思路: 都说是模板了...先缩点把有环图转换成DAG 然后拓扑排序即可 #include <bits/stdc++.h> using n ...

随机推荐

  1. openpyxl 实现excel字母列号与数字列号之间的转换

    https://www.cnblogs.com/apple2016/p/9686433.html

  2. C. Ehab and a 2-operation task

    链接 [https://codeforces.com/contest/1088/problem/C] 题意 n个数,最多n+1操作,要么前i个数加x,要么前i个数对x取余,最后使得严格递增 分析 直接 ...

  3. Github的建立及心得体会

    第一次接触Github,这次注册最大的难处就是全英文,着实看不懂.仅凭着认识的几个常用词去了解个具体内容实在是太困难了.所以第一个体会就是要好好学英语背单词,不想看到满屏的英文就感觉头疼,烦躁.第二个 ...

  4. Sprint会议计划

    经过饭后的宿舍激烈会议之后...... 1.我们的MASTER是组员董大为 2.这次sprint的目标是四则运算系统 3.每天例会时间地点:每天晚饭后在宿舍 4.实现四则运算的基本功能前期已经完成得差 ...

  5. I/O(输入/输出)

    1.创建引用ObjectInputStream ois =null; ObjectOutputStream oos = null; ByteArrayInputStream bais = null; ...

  6. Activiti中子流程:SubProcess,CallActiviti的区别

    子流程:SubProcess,CallActiviti的区别 https://community.alfresco.com/thread/221771-call-activiti-vs-subproc ...

  7. Server Tomcat v7.0 Server at libra failed to start

    https://stackoverflow.com/questions/13244233/server-tomcat-v7-0-server-at-localhost-failed-to-start- ...

  8. 求两个整数的最大公约数GCM

    思路分析: (1)求差判定法:  如果两个数相差不大,可以用大数减去小数,所得的差与小数的最大公约数就是原来两个数的最大公约数.例如:求78和60的最大公约数.78-60=18,18和60的最大公约数 ...

  9. CentOS virt-manager 安装Win2008r2的一种GUI方法

    1. 必须在物理机上面安装CentOS机器. 安装方法上一个blog里面简单写过. 注意一点,重复安装时 总是提示no disk found 我的解决办法使用 windows 安装盘 格式化了下磁盘重 ...

  10. Android控件第6类——杂项控件

    1.Toast Toast用于显示提示信息. Toast不会获得焦点,没法关闭,过段时间会自动消失. 使用方法:Toast.makeText获得Toast,并设置相关属性.调用Toast对象的show ...