Description
每头牛都有一个梦想:成为一个群体中最受欢迎的名牛!在一个有N(1<=N<=10,000)头牛的牛群中,给你M(1<=M<=50,000)个二元组(A,B),表示A认为B是受欢迎的。既然受欢迎是可传递的,那么如果A认为B受欢迎,B又认为C受欢迎,则A也会认为C是受欢迎的,哪怕这不是十分明确的规定。
你的任务是计算被所有其它的牛都喜欢的牛的个数。
Input
第一行,两个数,N和M。第2~M+1行,每行两个数,A和B,表示A认为B是受欢迎的。
Output
一个数,被其他所有奶牛认为受欢迎的奶牛头数。
Sample Input
3 3
1 2
2 1
2 3
Sample Output
1
Data Constraint
Hint
【样例说明】
3号奶牛是唯一被所有其他奶牛认为有名的。
思路
开始还以为这是并查集,但两只牛之间若互相喜欢就互相是对方的父亲,统计答案会出现混乱。
所以我们可以试着将A喜欢B,就连上一条A到B的路径,若是有一个集合的每个点可以到达该集合的其余点(也就是强连通分量)则该集合中的牛互相喜欢(看题意),这样我们就可以用tarjan缩点,由一堆点缩成一个个强连通分量。
可以证明,只要该强连通分量没有出度,则该强连通分量点的数量就是我们的答案
证明
因为我们已经将一个有向图缩成了一个个强连通分量,所以新图中就不会形成环(不然在缩点过程就已经变为一个强连通分量)。若一个强连通分量没有出度,则该强连通分量必然被其余强连通分量指向(除了存在有独立的强连通分量的情况,即该强连通分量不与其余任意一个强连通分量有边相连),因为依据题意,A指向B,B指向C,则A指向C。
证毕
代码
#include<cstdio>
#include<iostream>
#include<vector>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<deque>
#define M 50009
#define N 10009
using namespace std;
struct node
{
int to;
int next;
}edge[M];
int re[N];
int list[N];
int dfn[N];
bool visit[N];
int low[N];
int p[N];
int w[N];
int stack[N];
int tot,cnt;
int n,m;
int x,y;
int maxx;
int ans;
int num;
int k;
inline int find(int a)
{
if(re[a]==a)return a;
re[a]=find(a);
return a;
}
inline void tarjan(int x)
{
stack[++tot]=x;
low[x]=dfn[x]=++cnt;
visit[x]=1;
for(int i=list[x];i!=0;i=edge[i].next)
{
if(!dfn[edge[i].to])
{
tarjan(edge[i].to);
low[x]=min(low[x],low[edge[i].to]);
}
else
if(visit[edge[i].to])
low[x]=min(low[x],low[edge[i].to]);
}
if(dfn[x]==low[x])
{
num++;
do
{
re[stack[tot]]=num;
w[num]++;
maxx=max(maxx,re[stack[tot]]);
visit[stack[tot]]=0;
tot--;
}while(stack[tot+1]!=x);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
edge[i].to=y;
edge[i].next=list[x];
list[x]=i;
}
for(int i=1;i<=n;i++)
if(!dfn[i])tarjan(i);
for(int i=1;i<=n;i++)
{
for(int j=list[i];j!=0;j=edge[j].next)
{
if(p[re[i]])break;
if(re[i]!=re[edge[j].to])p[re[i]]++;
}
}
for(int i=1;i<=num;i++)//存在出度为0的强连通分量若存在两个以上,则必然为0,因为对于一个出度为零的强连通分量,必然有一个强连通分量不指向它(因为后一个强连通分量没有出度)而一个强连通分量至少包含一个点,依据题意,必须所有牛都喜欢一头牛才可以累计答案。
if(!p[i])
{
if(ans)
{
printf("0\n");
return 0;
}
ans=w[i];
}
printf("%d",ans);
return 0;
}