标签:
Input
* Line 1: Two space-separated integers, N and M
Output
* Line 1: A single integer that is the number of cows who are considered popular by every other cow.
Sample Input
3 3
Sample Output
1
Hint
Cow 3 is the only cow of high popularity.
Source
USACO 2003 Fall
题目大意:每头奶牛都希望自己成为最欢迎的那头牛。给你N头牛,M个崇拜关系(A,B)。
意思是牛A崇拜牛B。特别是,如果牛A崇拜牛B,牛B崇拜牛C,那么牛A也崇拜牛C。那么
问题来了:请计算出被所有牛崇拜的牛的个数。
思路:刚学的Kosaraju算法。考虑这道题,把崇拜关系(A,B)看做是一条有向边,并且,
我们发现牛的崇拜关系具有传递性。那么只要牛A有一条路径连向牛B,就可以判定牛A
崇拜牛B。于是,被所有牛崇拜的牛就是所有的点都存在一条路径连向它的有向路径。下
边简述下Kosaraju算法:
(1)对原图进行第一遍深度优先遍历,记录下每个节点的离开时间num[i]
(2)对原图的反向边构成的图进行第二遍深度优先遍历,从步骤(1)中离开时间最晚的点开
始。第(2)步中每搜索到一棵树都是一个强连通分量。用Hash[]把同一连通分量上的点缩
成一个点。
(3)缩点之后的图就构成了DAG(有向无环图),树的个数就是强连通分量的个数。
这道题中,将原图强连通分量缩点后构成了DAG,那么如果新图中出度为0的点只有一个,
则有解,为该出度为0的点的强连通分量中点的个数。若出度为0的点的个数不止一个,那
么无解。因为至少有两头牛互相不崇拜。
参考博文:http://blog.csdn.net/chang_mu/article/details/38709047
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN = 10010;
const int MAXM = 50050;
struct EdgeNode
{
int to;
int next1;
int fr;
int next2;
}Edges[MAXM];
int Head1[MAXN],Head2[MAXN],vis[MAXN];
int num[MAXN],Hash[MAXN],Count[MAXN],outdegree[MAXN];
int id;
void AddEdges(int u,int v)
{
Edges[id].to = v;
Edges[id].next1 = Head1[u];
Head1[u] = id;
Edges[id].fr = u;
Edges[id].next2 = Head2[v];
Head2[v] = id++;
}
//DFS第一遍,求出记录每个节点离开时间num[i]
void DfsOne(int cur,int& sig)
{
vis[cur] = 1;
for(int i = Head1[cur]; i != -1; i = Edges[i].next1)
{
if( !vis[Edges[i].to] )
DfsOne(Edges[i].to,sig);
}
num[++sig] = cur;
}
//DFS第二遍,求出双联通分量
void DfsTwo(int cur,int sig)
{
vis[cur] = 1;
Hash[cur] = sig; //Hash用来将同一个联通分量中的点缩成一个点
Count[sig]++;
for(int i = Head2[cur]; i != -1; i = Edges[i].next2)
{
if( !vis[Edges[i].fr])
DfsTwo(Edges[i].fr,sig);
else if(Hash[Edges[i].fr] != Hash[cur]) //outdegree判断缩点后新图各点是否有出度
outdegree[Hash[Edges[i].fr]] = 1;
}
}
int Kosaraju(int N)
{
int sig = 0,ans;
memset(vis,0,sizeof(vis));
for(int i = 1; i <= N; ++i)
if( !vis[i] )
DfsOne(i,sig);
memset(vis,0,sizeof(vis));
memset(Count,0,sizeof(Count));
memset(outdegree,0,sizeof(outdegree));
int i = sig;
sig = 0;
for(; i >= 1; --i)
if( !vis[num[i]])
DfsTwo(num[i],++sig);
int temp = 0;
for(int i = 1; i <= sig; i++) //新图只有一个点出度为0才算有解
if(!outdegree[i])
{
temp++;
ans = Count[i];
}
//printf("$%d ",temp);
if(temp == 1)
return ans;
else
return 0;
}
int main()
{
int N,M,u,v;
while(~scanf("%d%d",&N,&M))
{
id = 0;
memset(Head1,-1,sizeof(Head1));
memset(Head2,-1,sizeof(Head2));
for(int i = 0; i < M; ++i)
{
scanf("%d%d",&u,&v);
AddEdges(u,v);
}
int ans = Kosaraju(N);
printf("%d\n",ans);
}
return 0;
}
POJ2186 Popular Cows【Kosaraju】【强连通分量】
标签:
原文地址:http://blog.csdn.net/lianai911/article/details/43275319