強力に接続されたコンポーネント+ tarjanアルゴリズムの詳細な説明:
人気の牛
すべての牛の夢は、群れの中で最も人気のある牛になることです。N(1 <= N <= 10,000)の牛の群れでは、最大M(1 <= M <= 50,000)の順序対の形式(A、B)が与えられ、牛Aがその牛を考えていることを示します。 Bが人気です。人気は推移的であるため、AがBが人気であると考え、BがCが人気であると考える場合、入力の順序対によって明示的に指定されていなくても、AはCも人気があると考えます。あなたの仕事は、他のすべての牛に人気があると考えられている牛の数を計算することです。
入力
- 1行目:2つのスペースで区切られた整数、NとM
- 2行目…1 + M:スペースで区切られた2つの数字AとB。これは、AがBが人気があると考えていることを意味します。
出力
- 1行目:他のすべての牛に人気があると見なされる牛の数である単一の整数。
コード:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<stack>
using namespace std;
const int MAXN=5e4+5;
const int M=1e4+5;
typedef long long ll;
int col=0,num=0,top=0,dfn[M],low[M];
int deep[M];
int si[M];
int st[M];
int co[M];
struct edge
{
int to;
int next;
}e[MAXN];
int head[M];
int cnt=0;
void add(int u,int v)
{
e[cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt++;
}
void tarjan(int u)//缩点
{
dfn[u]=low[u]=++num;
st[++top]=u;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(!dfn[v])//没有搜过,则搜这个点
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(!co[v])//搜过这个点,若不在集合中,代表还在堆栈中。
{
low[u]=min(low[u],low[v]);
}
}
if(dfn[u]==low[u])//出栈
{
co[u]=++col;//记录第几个集合
si[col]++;//记录集合中元素数量
while(st[top]!=u)
{
co[st[top]]=col;
si[col]++;
top--;
}
top--;
}
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
head[i]=-1;
dfn[i]=0;
low[i]=0;
co[i]=0;
si[i]=0;
deep[i]=0;
}
int u,v;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
add(v,u);//反向建图
}
for(int i=1;i<=n;i++)
{
if(!dfn[i])
{
tarjan(i);
}
}
for(int i=1;i<=n;i++)
{
for(int j=head[i];j!=-1;j=e[j].next)
{
int v=e[j].to;
if(co[v]!=co[i])//判断是否在同一个集合里面
{
deep[co[v]]++;//若不在,则入度++
}
}
}
int ans=0,sum=0;
for(int i=1;i<=col;i++)
{
if(!deep[i]) {
ans=si[i];sum++;}
}
if(sum==1) printf("%d",ans);//若sum>1,说明有多个入度为0的分量,反过来就是无出度,说明不会被所有的的牛喜欢。
else printf("0");
}