题目大意

有N头牛,他们中间有些牛会认为另外一些牛“厉害”,且这种认为会传递,即若牛A认为牛B“厉害”,牛B认为牛C“厉害”,那么牛A也认为牛C“厉害”。现给出一些牛的数对(x, y)表示牛x认为牛y厉害。那么,求出所有的牛都认为该牛“厉害”的牛的个数。

题目分析

牛之间的关系,形成一个有向图。其中存在一些强连通分支,若强连通分支内的一个牛被所有牛认为“厉害”,那么整个强连通分支内的牛都被认为“厉害”。因此,将强连通分支合并为一个点,对图重构。 
    重构后的图为一个简单的有向图,题目转换为寻找能从所有点均可达的点的数目(实际数目为点代表的强连通分支内的点数目之和)。使用定理有向无环图中出度为0的点,可以从任何出度不为0的点到达。 
    因此,寻找该有向无环图中出度为0的点的个数,若出度为0的点的个数大于1,则这些出度为0的点之间互相不可达,则不存在所有点均可达的点;若出度为0的点的个数为1,则该出度为0的点代表的强连通分支内点的个数,即为题目的结果。

实现(c++)

#include<stdio.h>
#include<string.h>
#include<vector>
#include<stack>
#include<algorithm> using namespace std;
#define MAX_NODE 10005
#define min(a, b) a < b? a:b vector<int> gGraph[MAX_NODE];
stack<int> gStack;
bool gVisited[MAX_NODE]; //判断点是否被访问过
bool gInStack[MAX_NODE]; //判断点是否在栈中
int gDfn[MAX_NODE]; //在DFS过程中,点第一次被访问到的时间
int gLow[MAX_NODE]; //点x下方的点所能到达的序号最小的点的序号
int gIndex; int gClusterIndex;
int gClusterOfNode[MAX_NODE]; //每个点所属的强连通分支序号 //强连通分支结构体
struct Cluster{
int cluster_id;
int node_num;
vector<int> linked_cluster;
Cluster(int id, int num) :cluster_id(id), node_num(num){};
bool LinkedCluster(int cluster){
return find(linked_cluster.begin(), linked_cluster.end(), cluster) != linked_cluster.end();
}
void LinkCluster(int cluster){
linked_cluster.push_back(cluster);
}
~Cluster(){
linked_cluster.clear();
}
}; vector<Cluster> gClusters;
//tarjan 算法求强连通分支
void Tarjan(int u){
gDfn[u] = gLow[u] = ++gIndex;
gVisited[u] = true;
gInStack[u] = true;
gStack.push(u);
for (int i = 0; i < gGraph[u].size(); i++){
int v = gGraph[u][i];
if (gVisited[v] == false){
Tarjan(v);
gLow[u] = min(gLow[u], gLow[v]);
}
else if(gInStack[v]){ //注意,需要v在栈中才可以
gLow[u] = min(gLow[u], gDfn[v]);
}
}
if (gDfn[u] == gLow[u]){
int v, num = 0;
do{
v = gStack.top();
gClusterOfNode[v] = gClusterIndex;
gStack.pop();
gInStack[v] = false; //注意恢复
num++;
} while (u != v);
gClusters.push_back(Cluster(gClusterIndex, num)); gClusterIndex++;
}
} //将强连通分支的各个点染色之后,再重新建图
void ReconstructGraph(int n){
for (int u = 1; u <= n; u++){
for (int j = 0; j < gGraph[u].size(); j++){
int v = gGraph[u][j];
int uc = gClusterOfNode[u];
int vc = gClusterOfNode[v];
if (uc != vc && !gClusters[uc].LinkedCluster(vc))
gClusters[uc].LinkCluster(vc);
}
}
}
/*
int gRoot[MAX_NODE];
int GetRoot(int c){
if (gRoot[c] != c){
gRoot[c] = GetRoot(gRoot[c]);
}
return gRoot[c];
}
void Union(int c1, int c2){
int p1 = GetRoot(c1);
int p2 = GetRoot(c2);
if (p1 != p2){
gRoot[p1] = p2;
}
} bool DAG(){ //判断一个图是否为连通图,在此题中,可以不用判断
int n = gClusters.size(); for (int i = 0; i < n; i++){
gRoot[i] = i;
} for (int u = 0; u < n; u++){
for (int i = 0; i < gClusters[u].linked_cluster.size(); i++){
int v = gClusters[u].linked_cluster[i];
Union(u, v);
}
}
int r = GetRoot(0);
for (int i = 1; i < n; i ++){
if (r != GetRoot(i)){
return false;
}
}
return true;
}
*/
int main(){
int n, m, u, v;
while (scanf("%d %d", &n, &m) != EOF){
for (int i = 0; i <= n; i++){
gGraph[i].clear();
}
for (int i = 0; i < m; i++){
scanf("%d %d", &u, &v);
gGraph[u].push_back(v);
}
gIndex = 0;
gClusterIndex = 0;
memset(gInStack, false, sizeof(gInStack));
memset(gVisited, false, sizeof(gVisited));
gClusters.clear(); //Tarjan 求强连通分支
for (int i = 1; i <= n; i++){
if (!gVisited[i]){
Tarjan(i);
}
} //重新构图
ReconstructGraph(n); /*
if (!DAG()){
printf("0\n");
continue;
}
*/
int zero_outdegree_cluster = 0, result = 0;
for (int i = 0; i < gClusterIndex; i++){
if (gClusters[i].linked_cluster.empty()){
zero_outdegree_cluster++;
result = gClusters[i].node_num;
}
}
//若重构后的图中各个点不能构成一个连通图(将有向边变为无向边之后仍不能),那么就不存在一个点可以被其他所有点可达
//而此时,图中也肯定存在多于1个点,其出度为0.
//故,只需要判断重构后的图中,出度为0的点是否为1个即可。若出度为0的点有且只有一个,则返回该“点”(实际为一个强连通分支)
//中的点的数目,否则,返回0 if (zero_outdegree_cluster > 1){
result = 0;
}
printf("%d\n", result);
}
return 0;
}

poj_2186 强连通分支的更多相关文章

  1. Kosaraju 算法查找强连通分支

    有向图 G = (V, E) 的一个强连通分支(SCC:Strongly Connected Components)是一个最大的顶点集合 C,C 是 V 的子集,对于 C 中的每一对顶点 u 和 v, ...

  2. poj 2553 强连通分支与缩点

    思路:将所有强连通分支找出来,并进行缩点,然后找其中所有出度为0的连通分支,就是题目要求的. #include<iostream> #include<cstdio> #incl ...

  3. poj 2186 强连通分支 和 spfa

    思路: 建图时,分别建正向图edge和转置图T.用正向图edge来DFS,找出第一个被发现的强连通分支(如果该图存在题目要求的点,那么一定就是第一个被发现的).然后用spfa跑转置图T,判断被发现的点 ...

  4. poj 1236 Network of Schools【强连通求孤立强连通分支个数&&最少加多少条边使其成为强连通图】

    Network of Schools Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 13800   Accepted: 55 ...

  5. 基于visual Studio2013解决算法导论之050强连通分支

     题目 强连通分支 解决代码及点评 // 强连通分支.cpp : 定义控制台应用程序的入口点. // #include<iostream> #define MAX 100 using ...

  6. 有向图强连通分支的Tarjan算法讲解 + HDU 1269 连通图 Tarjan 结题报告

    题目很简单就拿着这道题简单说说 有向图强连通分支的Tarjan算法 有向图强连通分支的Tarjan算法伪代码如下:void Tarjan(u) {dfn[u]=low[u]=++index//进行DF ...

  7. poj_2553 强连通分支&出度为0的点

    题目大意 N个点的有向图中,定义“好点”为: 从该点v出发可以到达的所有点u,均有一条路径使得u可达v. 求出图中所有的“好点”,并按照顺序从小到大输出出来. 题目分析 图存在多个强连通分支,强连通分 ...

  8. poj_1236 强连通分支

    题目大意 有N个学校,这些学校之间用一些单向边连接,若学校A连接到学校B(B不一定连接到A),那么给学校A发一套软件,则学校B也可以获得.现给出学校之间的连接关系,求出至少给几个学校分发软件,才能使得 ...

  9. 【2186】Popular Cows(强连通分支及其缩点)

    id=2186">[2186]Popular Cows(强联通分支及其缩点) Popular Cows Time Limit: 2000MS   Memory Limit: 65536 ...

随机推荐

  1. php回调函数原理和实例

    原理 自己调用自己 称之为“递归”,而不是回调 你也知道回调的关键是这个回既然是回,那么就有一个谁是主体的问题,因为回调是往回调用的意思我调用了函数A,而函数A在执行过程中调用了我提供的函数B,这个函 ...

  2. atitit,it人怎么样才容易事业成功?? 有以下五种性格的人容易成功

    atitit,it人怎么样才容易事业成功?? 有以下五种性格的人容易成功 有以下五种性格的人容易成功 一.不撞南墙不回头的人:由于这种人有脚踏实地,做事拼命.不撞南墙不回头的性格特点, 势有不到黄河心 ...

  3. 关于浏览器对静态HTML页面的缓存问题

    症状: 刚才为了测试TOMCAT的BASIC安全验证,修改了tomcat-users.xml和/WEB-INF/web.xml之后进行测试,<url-pattern>/*<url-p ...

  4. 存储管理器实验——SDRAM

    序言:2440有nand和nor两种启动方式,在裸机部分,都是使用的nand启动. 现在,我们想在nand flash启动的时候,通过SRAM访问存储在外设SDRAM中的程序. nand启动,先把前4 ...

  5. 4个著名VCS的比较

    特征 CVS Git Mercurial Subversion 是否原子提交 CVS: 没有. CVS提交不是原子的 Git: 是的. 提交都是原子的 Mercurial: 是的 Subversion ...

  6. PHP,JavaScript,CSS三种HTML内嵌语言的语法,变量,循环,函数记录

    PHP PHP简介: PHP 是服务器端脚本语言. PHP(全称:PHP:Hypertext Preprocessor,即"PHP:超文本预处理器")是一种通用开源脚本语言. PH ...

  7. 深入理解JVM--JVM垃圾回收机制(转)

    Java语言出来之前,大家都在拼命的写C或者C++的程序,而此时存在一个很大的矛盾,C++等语言创建对象要不断的去开辟空间,不用的时候有需要不断的去释放控件,既要写构造函数,又要写析构函数,很多时候都 ...

  8. Memcached 1.4.20 发布,集中式缓存系统

    内存缓存Memcached 1.4.20发布.2014-05-12 上一个版本是2014-05-01的1.4.19  此版本只修正了一个1.4.18和1.4.19中引入的Bug. 此版本只是修复了导致 ...

  9. mui区域滚动条

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  10. 关于VS2013的安装遇到的问题

    老师突然说实验一需要用代码实现,我之前配置的cocos的编程环境是cocos+VS2013,是很稳定的 但是,我安装unity5.5的时候,不小心选择了顺带安装了VS2015,就等于我电脑里面有了两个 ...