poj 2186 Popular Cows 【强连通分量Tarjan算法 + 树问题】
| Time Limit: 2000MS | Memory Limit: 65536K | |
| Total Submissions: 27496 | Accepted: 11059 |
Description
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
* Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.
Output
Sample Input
3 3
1 2
2 1
2 3
Sample Output
1
Hint
#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算法 + 树问题】的更多相关文章
- poj 2186 Popular Cows (强连通分量+缩点)
http://poj.org/problem?id=2186 Popular Cows Time Limit: 2000MS Memory Limit: 65536K Total Submissi ...
- POJ 2186 Popular Cows(强连通分量缩点)
题目链接:http://poj.org/problem?id=2186 题目意思大概是:给定N(N<=10000)个点和M(M<=50000)条有向边,求有多少个“受欢迎的点”.所谓的“受 ...
- POJ 2186 Popular Cows --强连通分量
题意:给定一个有向图,问有多少个点由任意顶点出发都能达到. 分析:首先,在一个有向无环图中,能被所有点达到点,出度一定是0. 先求出所有的强连通分支,然后把每个强连通分支收缩成一个点,重新建图,这样, ...
- POJ 2186 Popular Cows 强连通分量模板
题意 强连通分量,找独立的块 强连通分量裸题 #include <cstdio> #include <cstdlib> #include <cstring> #in ...
- POJ2186 Popular Cows 强连通分量tarjan
做这题主要是为了学习一下tarjan的强连通分量,因为包括桥,双连通分量,强连通分量很多的求法其实都可以源于tarjan的这种方法,通过一个low,pre数组求出来. 题意:给你许多的A->B ...
- 强连通分量分解 Kosaraju算法 (poj 2186 Popular Cows)
poj 2186 Popular Cows 题意: 有N头牛, 给出M对关系, 如(1,2)代表1欢迎2, 关系是单向的且能够传递, 即1欢迎2不代表2欢迎1, 可是假设2也欢迎3那么1也欢迎3. 求 ...
- tarjan缩点练习 洛谷P3387 【模板】缩点+poj 2186 Popular Cows
缩点练习 洛谷 P3387 [模板]缩点 缩点 解题思路: 都说是模板了...先缩点把有环图转换成DAG 然后拓扑排序即可 #include <bits/stdc++.h> using n ...
- POJ 2186 Popular Cows (强联通)
id=2186">http://poj.org/problem? id=2186 Popular Cows Time Limit: 2000MS Memory Limit: 655 ...
- 有向图强连通分量Tarjan算法
在https://www.byvoid.com/zhs/blog/scc-tarjan中关于Tarjan算法的描述非常好,转述如下: 首先解释几个概念: 有向图强连通分量:在有向图G中,如果两个顶点间 ...
随机推荐
- A guide to analyzing Python performance
来源:http://www.huyng.com/posts/python-performance-analysis/ While it's not always the case that every ...
- 使用spring+quartz配置多个定时任务
Spring被用在了越来越多的项目中, quartz也被公认为是比较好用的定时器设置工具, 在这里通过一个demo说明如何使用spring和quartz配置多个定时任务. 环境: eclipse + ...
- socket listen/accept
listen函数 摘要:listen函数使用主动连接套接口变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程.在TCP服务器编程中listen函数把进程变为一个服务器,并指定 ...
- hdu5646(数学)
小学数学,脑补 一开始看到这题,猜了个规律想写但是我是拒绝的. 因为我无法证明. 好吧,主要还是小学数学没学好吧. 要理解这题,首先得搞懂一个重要问题.假设C=A+B,怎样选择两个正整数使得A*B最大 ...
- 【BZOJ4974】字符串大师 KMP
[BZOJ4974]字符串大师 Description 一个串T是S的循环节,当且仅当存在正整数k,使得S是T^k(即T重复k次)的前缀,比如abcd是abcdabcdab的循环节.给定一个长度为n的 ...
- Cocos2d-x Lua中多场景切换生命周期
在多个场景切换时候,场景的生命周期会更加复杂.这一节我们介绍一下场景切换生命周期.多个场景切换时候分为几种情况:情况1,使用pushScene函数从实现GameScene场景进入SettingScen ...
- mock数据(模拟后台数据)
mock数据(模拟后台数据) - Emily恩 - 博客园 https://www.cnblogs.com/enboke/p/vue.html Mock.js http://mockjs.com/ 前 ...
- Python菜鸟之路:Django 表单验证
前言 Django中完成表单验证,常用的有两种方法: 一种是通过HTML + JS + Ajax实现. 另一种是通过Django自身的forms模块来生成相应个HTML标签来完成表单验证.这是本节着重 ...
- JavaWeb 三层框架
1. MVC 设计模式 Model: JavaBean; View: Jsp; Controller: Servlet; 2. JavaWeb 三层框架 所谓三层是表述层(WEB 层), 业务逻辑层( ...
- 两个offer如何做选择?年薪20万vs年薪15万
(附注:本文转载于:http://www.eoeandroid.com/thread-296678-1-1.html) 前些天和一个年轻的朋友谈跳槽.朋友说她需要在两个offer里面做选择.一个是年薪 ...