题目描述
有n头牛,每头牛都有自己崇拜的牛,其中崇拜关系是单向的,这种关系共有m个
同时如果A崇拜B,B崇拜C,那么A也崇拜C
求有多少头同时被所有牛(n头)崇拜的牛的数量
我们认为,所有牛都崇拜自己
输入:
第一行两个正整数n(1≤n≤10000),m(1≤m≤100000)
接下来m行每行两个正整数a,b(1≤a,b≤n)表示a崇拜b
输出:
仅一行,同时被所有牛崇拜的牛的数量
样例输入:
3 3
1 2
2 1
2 3
样例输出:
1
解释:
1<->2->3,明显3被1,2,自己崇拜
分析
朴素思路:直接暴力遍历整个图
但我们迅速发现,如果遇到一个环,那么我们要求的东西就非常难继承下去了
环?这不是强联通分量吗?
于是想到Tarjan缩点,将强联通分量缩成一个强联通点,然后我们求出度为0的点即可
#include <iostream>
#include <cstdio>
#define rep(i,a,b) for (i=a;i<=b;i++)
using namespace std;
int n,m;
int list[10001],next[50001],u[50001],v[50001];
int d[10001],s[10001],c[10001];
int stk[10001],top,instk[10001];
int dfn[10001],low[10001],target,cnt;
int ans;
bool b[10001];
void tarjan(int i)
{
int j=list[i];
dfn[i]=low[i]=++target;
stk[++top]=i;instk[i]=1;
while (j>0)
{
if (dfn[v[j]]==0)
{
tarjan(v[j]);
low[i]=min(low[i],low[v[j]]);
}
else
if (instk[v[j]])
low[i]=min(low[i],dfn[v[j]]);
j=next[j];
}
if (low[i]==dfn[i])
{
cnt++;
int cnnt=0,l;
do
{
l=stk[top];
top--;
cnnt++;
d[l]=cnt;
instk[l]=0;
}
while (i!=l);
s[cnt]=cnnt;
}
}
void init()
{
int i;
scanf("%d%d",&n,&m);
rep(i,1,m)
{
scanf("%d%d",&u[i],&v[i]);
next[i]=list[u[i]];
list[u[i]]=i;
}
}
void doit()
{
int i;
int b=0;
rep(i,1,n)
if (dfn[i]==0) tarjan(i);
rep(i,1,m)
if (d[u[i]]!=d[v[i]])
c[d[u[i]]]++;
rep(i,1,cnt)
if (c[i]==0)
{
b++;
ans=s[i];
}
if (b>1||b==0)
printf("0");
else
printf("%d",ans);
}
int main()
{
init();
doit();
}