Description
每头牛都想成为牛群中的红人。给定n头牛和m个有序对(a,b),(a,b)表示牛a认为牛b是红人。该关系有传递性,所以如果牛a认为牛b是红人,牛b认为牛c是红人,那么牛a认为牛c也是红人。求被其他所有牛认为是红人的牛的总数
Input
第一行两个整数n和m表示牛数和关系数,之后m行每行两个整数a和b表示牛a认为牛b是红人
Output
输出被其他所有牛认为是红人的牛的个数
Sample Input
3 3
1 2
2 1
2 3
Sample Output
1
Solution
首先用tarjan算法求强联通分量,缩点后统计出度为0的点的个数,如果大于一则不存在符合的情况,因为每个缩点内部的牛都互相认为是红人,而如果出现两个及以上的出度为0的点的话那么这几个强联通分量必然不能从所有点可达,如果等于一则统计这个缩点包含的牛数即为答案
Code
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;
#define maxn 11111
vector<int>g[maxn];
stack<int>st;
int n,m,scc,index;
int low[maxn],dfn[maxn],instack[maxn],fa[maxn];
int cnt[maxn];//每个强联通分量的出度
void init()//初始化
{
scc=index=0;
while(!st.empty())st.pop();
for(int i=0;i<maxn;i++)g[i].clear();
memset(dfn,0,sizeof(dfn));
memset(instack,0,sizeof(instack));
memset(low,0,sizeof(low));
memset(cnt,0,sizeof(cnt));
}
void tarjan(int u)//求强联通分量
{
dfn[u]=low[u]=++index;
instack[u]=1;
st.push(u);
int v,size=g[u].size();
for(int i=0;i<size;i++)
{
v=g[u][i];
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(instack[v])
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u])
{
scc++;
do
{
v=st.top();
st.pop();
fa[v]=scc;
instack[v]=0;
}while(v!=u);
}
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
init();//初始化
for(int i=0;i<m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
g[u].push_back(v);//建边
}
for(int i=1;i<=n;i++)//求强联通分量
if(!dfn[i])
tarjan(i);
for(int i=1;i<=n;i++)
for(int j=0;j<g[i].size();j++)
{
int v=g[i][j];
if(fa[i]!=fa[v])//统计出度
cnt[fa[i]]++;
}
int ans=0,u;
for(int i=1;i<=scc;i++)
if(!cnt[i])//统计出度为零的缩点
{
u=i;
ans++;
}
if(ans==1)//只有一个出度为0的点则满足条件
{
ans=0;
for(int i=1;i<=n;i++)
if(fa[i]==u)//统计该缩点内部的牛数
ans++;
printf("%d\n",ans);
}
else//否则不存在满足条件的牛
printf("0\n");
}
return 0;
}