Popular Cows
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 27496   Accepted: 11059

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.
 
题目:样例解释,3头牛,3条边。 1崇拜2, 2崇拜1, 2崇拜3。  3号牛能获得出自己之外的所有牛的崇拜,这样的牛有多少?输出数量。
注意:崇拜的关系是可以往上层传递的。1->2, 2->3, 可以得到:1->3.
 
通过Tarjan算法,我们会把所有的节点划分到不同的枪连通分量中。根据强连通分量的定义,处在同一个强连通分量中的节点,一会是互相仰慕的.
把每个强连通分量看成是一个节点。这样就构造成一棵树(树边是有向的),看这个树有几个出度为0的强连通分量。如果仅有一个,则会存在正确
答案。否则不可能存在满足题目的可能,只能输出0。
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#define N 10000+10
#define M 51000+10 using namespace std;
int n, m;
struct node
{
int to;
int next;
}edge[M];//保证存下所有的边 int head[N], dfn[N], low[N], vis[N];
int stack[N], num[N], du[N];
int counter, top, cut, cnt;
/*
dfn[]:记录搜索时各顶点的访问次序,即深度优先数
low[u]:每个节点定义一个low值 low[u]是从u或u的子孙出发通过回边可以到达
的最低深度优先数
注意:dfn[]在搜索前进时进行统计 low[]值是在回退的时候进行计算
du[]:表示出度
*/
void init()
{
memset(head, -1, sizeof(head));
memset(vis, 0, sizeof(vis));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(num, 0, sizeof(num));
memset(du, 0, sizeof(du));
counter=1;//begin 1
cnt=0;//边 计数
top=0;// stack top
cut=0;
} void addedge(int u, int v)
{
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}//静态数组 倒着建边 void dfs(int u)
{
dfn[u]=low[u]=counter++;//counter的值从1开始
vis[u]=1;//标记访问
stack[top++]=u;
//遍历从u节点发出的边
for(int i=head[u]; i!=-1; i=edge[i].next){
int v=edge[i].to;
if(!vis[v]){//这是一条树边
dfs(v);
low[u]=min(low[u], low[v]);//回溯的时候比较
}
else if(vis[v]){
low[u]=min(low[u], dfn[v]);
}
}
if(low[u]==dfn[u]){
cut++;//表示已经找到了一个强连通分量
while(top>0 && stack[top]!=u){
top--;
vis[stack[top]]=2;//
num[stack[top]]=cut;//确定当前这个节点属于哪个强连通分量
}
}
} int main()
{
int i, j;
while(scanf("%d %d", &n, &m)!=EOF)
{
init();//进行初始化
int u, v;
for(i=1; i<=m; i++){
scanf("%d %d", &u, &v);
addedge(u, v);
}//建立单向边 for(i=1; i<=n; i++){
if(!vis[i]){
dfs(i);
}
}//不知道为什么在此处计数一下连通分量的数目 如果大于1 直接输出0 这样提交 会WA。不写就对 for(i=1; i<=n; i++){
for(j=head[i]; j!=-1; j=edge[j].next){
int v=edge[j].to;
if(num[i]!=num[v])//如果连通分量的编号不等
du[num[i]]++;//出度++
}
}
int pos; int dd=0;
for(i=1; i<=cut; i++){
if(du[i]==0){
dd++; pos=i;
}
}
//printf("pos = %d\n", pos);
if(dd==1){
int ans=0;
for(i=1; i<=n; i++){
if(num[i]==pos)
ans++;
}
printf("%d\n", ans );
}
else printf("0\n");
}
return 0;
}

使用STL-stack模拟的,注意在栈弹出节点的地方的写法,在循环跳出之后再弹出一次,因为遇到u==v的时候就跳出了,而u没有被弹出。

上面的数组模拟的stack操作也可以再修改一下。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stack>
#include <algorithm>
#define N 10000+10
#define M 51000+10 using namespace std;
int n, m;
struct node
{
int to;
int next;
}edge[M];//保证存下所有的边 int head[N], dfn[N], low[N], vis[N];
int num[N], du[N];
int counter, top, cut, cnt;
/*
dfn[]:记录搜索时各顶点的访问次序,即深度优先数
low[u]:每个节点定义一个low值 low[u]是从u或u的子孙出发通过回边可以到达
的最低深度优先数
注意:dfn[]在搜索前进时进行统计 low[]值是在回退的时候进行计算
du[]:表示出度
*/
stack<int>q;
void init()
{
memset(head, -1, sizeof(head));
memset(vis, 0, sizeof(vis));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(num, 0, sizeof(num));
memset(du, 0, sizeof(du));
counter=1;//begin 1
cnt=0;//边 计数
top=0;// stack top
cut=0;
} void addedge(int u, int v)
{
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}//静态数组 倒着建边 void dfs(int u)
{
dfn[u]=low[u]=counter++;//counter的值从1开始
vis[u]=1;//标记访问
q.push(u);
//遍历从u节点发出的边
for(int i=head[u]; i!=-1; i=edge[i].next){
int v=edge[i].to;
if(!vis[v]){//这是一条树边
dfs(v);
low[u]=min(low[u], low[v]);//回溯的时候比较
}
else if(vis[v]){
low[u]=min(low[u], dfn[v]);
}
}
if(low[u]==dfn[u]){
cut++;//表示已经找到了一个强连通分量
while(!q.empty() && q.top()!=u){
vis[q.top()]=2;//
num[q.top()]=cut;//确定当前这个节点属于哪个强连通分量
q.pop();
}
vis[q.top()]=2;//
num[q.top()]=cut;//确定当前这个节点属于哪个强连通分量
q.pop(); //还要将u节点弹出
}
} int main()
{
int i, j;
while(scanf("%d %d", &n, &m)!=EOF)
{
init();//进行初始化
int u, v;
for(i=1; i<=m; i++){
scanf("%d %d", &u, &v);
addedge(u, v);
}//建立单向边 int cur=0;
for(i=1; i<=n; i++){
if(!vis[i]){
dfs(i); cur++;
}
} for(i=1; i<=n; i++){
for(j=head[i]; j!=-1; j=edge[j].next){
int v=edge[j].to;
if(num[i]!=num[v])//如果连通分量的编号不等
du[num[i]]++;//出度++
}
}
int pos; int dd=0;
for(i=1; i<=cut; i++){
if(du[i]==0){
dd++; pos=i;
}
}
if(dd==1){
int ans=0;
for(i=1; i<=n; i++){
if(num[i]==pos)
ans++;
}
printf("%d\n", ans );
}
else printf("0\n");
}
return 0;
}

poj 2186 Popular Cows 【强连通分量Tarjan算法 + 树问题】的更多相关文章

  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(强连通分量缩点)

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

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

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

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

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

  5. POJ2186 Popular Cows 强连通分量tarjan

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

  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. tarjan缩点练习 洛谷P3387 【模板】缩点+poj 2186 Popular Cows

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

  8. POJ 2186 Popular Cows (强联通)

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

  9. 有向图强连通分量Tarjan算法

    在https://www.byvoid.com/zhs/blog/scc-tarjan中关于Tarjan算法的描述非常好,转述如下: 首先解释几个概念: 有向图强连通分量:在有向图G中,如果两个顶点间 ...

随机推荐

  1. Unity3D学习笔记——Android重力感应控制小球

    一:准备资源 两张贴图:地图和小球贴图. 二:导入资源 在Assets下建立resources文件夹,然后将贴图导入. 三:建立场景游戏对象 1.建立灯光: 2.创建一个相机,配置默认. 3.建立一个 ...

  2. ios -将navigationbar的translucent属性设为No后,子控制器视图整体下移问题

    如果不将navigationbar.translucent = YES 会觉得颜色很浅,因为这是半透明状态 若navigationbar.translucent = NO,颜色问题解决,但是子控制器视 ...

  3. JAVA的Hashtable在遍历时的迭代器线程问题

    这篇博客主要讲什么 Hashtable及其内部类的部分源码分析 Hashtable在遍历时的java.util.ConcurrentModificationException异常的来由和解决 单机在内 ...

  4. RocketMq的安装使用

    RocketMq的安装使用 .一.预备环境 1.系统 Windows 2. 环境 JDK1.8.Maven.Git 1.下载 1.1地址:http://rocketmq.apache.org/rele ...

  5. JavaScript通过preventDefault()使input[type=text]禁止输入但保留光标

    一.说明 取消事件的默认动作. 该方法将通知 Web 浏览器不要执行与事件关联的默认动作(如果存在这样的动作).例如,如果 type 属性是 "submit",在事件传播的任意阶段 ...

  6. JS上传图片预览及图片限制

    HTML代码: <form action="__SELF__" method="post" enctype='multipart/form-data'&g ...

  7. python 报错——Python TypeError: 'module' object is not callable 原因分析

    原因分析:Python导入模块的方法有两种: import module 和 from module import 区别是前者所有导入的东西使用时需加上模块名的限定,而后者则不需要 例: >&g ...

  8. 如何高效地分析Android_log中的问题?——查看Android源码

    在日常解bugs时,需要通过log日志来分析问题,例如查看crash发生时的堆栈信息时,就会有Android的源码的调用,这是就要去查看Android源码. 1.进入Android源码网址查看,例如  ...

  9. mssql 中文乱码 字库集 问题解决方法

    The database could not be exclusively locked to perform the operation(SQL Server 5030错误解决办法)   SQL S ...

  10. C# 二进制序列化(BinaryFormatter),Xml序列化(XmlSerializer),自己模拟写一个Xml序列化过程。

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...