题目连接:

http://poj.org/problem?id=2186

题目大意:

每头奶牛都希望自己成为最欢迎的那头牛。给你N头牛,M个崇拜关系(A,B)。意思是牛A

崇拜牛B。特别是,如果牛A崇拜牛B,牛B崇拜牛C,那么牛A也崇拜牛C。那么问题来了:

请计算出被所有牛崇拜的牛的个数。

思路:

把崇拜关系(A,B)看做是一条有向边,并且,我们发现牛的崇拜关系具有传递性。那么只要

牛A有一条路径连向牛B,就可以判定牛A崇拜牛B。于是,被所有牛崇拜的牛就是所有的点

都存在一条路径连向它的有向路径。这道题中,将原图强连通分量缩点后构成了DAG,那么

如果新图中出度为0的点只有一个,则有解,为该出度为0的点的强连通分量中点的个数。若

出度为0的点的个数不止一个,那么无解。因为至少有两头牛互相不崇拜。

之前用Kosaraju算法来做,这次用Tarjan算法来做。


描述一下Tarjan算法:

对原图进行优先搜索,每个强连通分量是原图深度优先搜索的子树。那么我们就可以通过确

定每个强连通分量子树的根,根据这些根,从树的最底层开始,一个一个去处强连通分量。

使用两个数组:dfn[v]来表示顶点v被访问的时间,low[v]表示为顶点v邻接的未删除的顶点

u的low[u]和顶点v的low[v]的最小值(low[v]初始化为dfn[v])。这是为了使同一强连通分量的

low[]值都相同,且值与该强连通分量的根的访问时间dfn[]相等,从而就确定了强连通分量

的根和其属于强连通分量的点。

这样,如果发现了low[v] == dnf[v],那么,该点v就是一个强连通分量的根。因为如果该点

v不是强连通分量的根,那么一定属于另一个强连通分量,而且该点v的根就是当前顶点v的祖

宗,那就存在包含当前顶点v到其祖宗的回路,可知顶点v的low[v]值一定是比顶点v的访问时

间dfn[v]更小的值,应为顶点v所在强连通分量的根的dfn[]值。

确定了强连通分量的根后,怎么来取出强连通分量呢?

如果当前节点v为一个强连通分量的根,那么它的强连通分量一定是以该节点v为根节点的子

树。在深度优先遍历的时候维护一个堆栈,每次访问一个新节点,就压入堆栈。由于当前节

点v是这个强连通分量中最先压入堆栈的,那么在当前节点v以后压入堆栈并且仍在堆栈中的

节点都属于这个强连通分量。假设一个节点u在当前节点v压入堆栈后压入并且还存在,同时

节点u不属于该强连通分量。那么一定属于另一个强连通分量,但当前节点v是节点u的根的

祖宗,那么这个强连通分量在之前已经被取出。

具体做法:

(1)访问一个没有被访问过的节点v;否则结束。

(2)初始化dfn[v]和low[v]。

对于节点v的所有邻接顶点u:

1.如果没有访问过,转到步骤(2),同时维护low[v]。

2.如果访问过,但没有删除,维护low[v]。

如果low[v] == dfn[v],那么取出相应的强连通分量。

参考:ACM-ICPC程序设计系列——图论及应用 P115~117

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN = 10010;
const int MAXM = 50050;struct EdgeNode
{int to;int next;
}Edges[MAXM];int Head[MAXN],vis[MAXN],low[MAXN];
int dfn[MAXN],Stack[MAXN],outdegree[MAXN],Count[MAXN],m,id;void AddEdges(int u,int v)
{Edges[id].to = v;Edges[id].next = Head[u];Head[u] = id++;
}int TarBFS(int pos,int lay,int &scc)
{vis[pos] = 1;low[pos] = lay;     //初始为开始时间dfn[pos] = lay;     //初始为开始时间Stack[++m] = pos;   //将当前未处理节点入栈,回溯时可以判断栈顶到栈中的结点是否为同一个强连通分量for(int i = Head[pos]; i != -1; i = Edges[i].next)  //枚举每一条边{if(!vis[Edges[i].to])TarBFS(Edges[i].to,++lay,scc);if(vis[Edges[i].to] == 1)low[pos] = min(low[pos],low[Edges[i].to]);}if(dfn[pos] == low[pos])    //缩点,low[]相同的结点属于同一个强连通分量{++scc;do{Count[scc]++;       //强连通分量内的点数low[Stack[m]] = scc;vis[Stack[m]] = 2;}while(Stack[m--] != pos);}return 0;
}int Tarjan(int N)
{int scc = 0, temp = 0, ans, lay = 1;m = 0;memset(vis,0,sizeof(vis));memset(low,0,sizeof(low));memset(dfn,0,sizeof(dfn));for(int i = 1; i <= N; ++i)if(vis[i] == 0)TarBFS(i,lay,scc);for(int i = 1; i <= N; ++i){for(int j = Head[i]; j != -1; j = Edges[j].next)if(low[i] != low[Edges[j].to]){outdegree[low[i]] = 1;break;}}for(int i = 1;i <= scc; ++i){if(! outdegree[i]){if(++temp > 1)break;ans = Count[i];}}if(temp != 1)return 0;return ans;
}
int main()
{int N,M,u,v;while(~scanf("%d%d",&N,&M)){memset(Head,-1,sizeof(Head));memset(outdegree,0,sizeof(outdegree));memset(Count,0,sizeof(Count));id = 0;for(int i = 0; i < M; ++i){scanf("%d%d",&u,&v);AddEdges(u,v);}int ans = Tarjan(N);printf("%d\n",ans);}return 0;
}

POJ2186 Popular Cows【Tarjan】【强连通分量】相关推荐

  1. POJ 2186 Popular Cows(强连通分量缩点,Tarjan算法)

    [题目链接] http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=16578 [解题报告] 给你一个有向图,问你有多少个点可以被其它 ...

  2. Poj 2186 Popular Cows(Tarjan 强连通缩点)

    传送门:Poj 2186 题意:给你n头牛,m种关系,A牛认为B牛是popular的,B牛认为C牛是popular的,则A也认为C是popular的,问最终有几头被所有牛认为是popular的牛 题解 ...

  3. POJ-2186 Popular Cows (Tarjan缩点) 文末有测试数据

    题目链接 NNN个牛,MMM个关系 (A,B)A(A,B)A(A,B)A认为BBB是受欢迎的.求受所有牛欢迎的牛的数量. 思路 同一个强联通分量里面的牛是相互受欢迎的,我们将所有的联通分量求出来之后, ...

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

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

  5. 【tarjan强连通分量】洛谷P1726 上白泽慧音

    [tarjan强连通分量]洛谷P1726 上白泽慧音 题目传送门 妥妥的强连通模板啊(详细解释戳这里) #include <bits/stdc++.h> #define MAXN 5005 ...

  6. 2021.8.9【提高B组模拟1】T2 QYQ在艾泽拉斯(Tarjan强连通分量)(并查集)

    QYQ在艾泽拉斯 题目大意 输入样例 3 2 1 2 3 1 1 2 1 0 输出样例 4 样例说明: QYQ从3号点开始,走到2号点,最后走到1号点,结束旅程,共获得1+2+1=4价值的宝物 题目数 ...

  7. POJ2186:Popular Cows(tarjan+缩点)

    题目解析: 这题题意没什么好说的,解法也挺简单的,只要会tarjan算法+只有一个出度为0的强连通分量题目有解这题就迎刃而解了. #include <iostream> #include ...

  8. POJ2186-Popular Cows(流行的奶牛)【tarjan,强连通分量,图论】

    正题 题目链接 大意 有n头奶牛,奶牛们会认为有些奶牛很受欢迎,受欢迎会互相传递,如:如果A认为B很受欢迎,而B认为C受欢迎,那么A也会认为C是受欢迎的.然后求每一个奶牛都认为受欢迎的奶牛数量. 解题 ...

  9. Tarjan 强连通分量

    强连通分量 图中找到一个最大的子图,使得子图中任意两个节点相互到达. 一个点也是一个强连通分量 Tarjan 构成强连通分量是必定是dfs树的一棵子树,在对树进行dfs的时候记录访问时间dfn和以该节 ...

最新文章

  1. Freebsd10.3(FreeBSD11 Beta1)使用手记
  2. 200912阶段一C++友元、运算符重载
  3. redis安装与基本配置
  4. 学python需要记笔记吗_开始学python,一些笔记
  5. c语言josn序列化和反序列化,Flutter 中 JSON 的序列化和反序列化
  6. 诗与远方:无题(十九)
  7. Android FrameWork——StatusBar
  8. 有图有真相——关于“视频专辑:零基础学习C语言 ”
  9. 英文文档: 如何使用 OpenSSL 创建与吊销数字证书
  10. 为酒店设计一套计算机网络管理系统,酒店管理系统设计方案(9页)-原创力文档...
  11. 1089. 烽火传递
  12. 来势汹汹 两大版本 百公里加速最快小于3.5s 电动车最大黑马居然是TA!
  13. 全民健身时代到来,运动类APP如何秀出肌肉?
  14. JavaSE常用类练习
  15. echarts.js 官网
  16. 快收藏!最适合计算机大学生的Java毕业设计项目--音乐视频网站系统!
  17. Eclipse – 建構 Android 的開發環境
  18. 关于Unity3D的初步学习研究周记
  19. 5.6-5.8工作记录2—分页模糊查询
  20. Java实现后端生成excel表格模板--下拉框实现

热门文章

  1. 打车软件是优惠利民还是扰乱市场
  2. 免费领取淘宝高德打车/滴滴/花小猪100元打车优惠券红包,分享源码探讨
  3. modbus总线协议(三)modbus tcp
  4. 基于eNSP的路由交换数据
  5. 关闭 iTunes 自动同步
  6. 微信公众号接入自动聊天机器人
  7. 如何使用局部敏感哈希(LSH)算法进行特征降维?
  8. unmountComponentAtNode的用法
  9. 计算机老师招聘技能考试内容,技能测试-计算机(教师招考真题)
  10. 小车舵机控制linux软件,在Linux(Ubuntu)上使用串口控制ROBOTIS Dynamxiel舵机