题目简述:n头奶牛,给出若干个欢迎关系a b,表示a欢迎b,欢迎关系是单向的,但是是可以传递的。另外每个奶牛都是欢迎他自己的。求出被所有的奶牛欢迎的奶牛的数目。
模型转换:N个顶点的有向图,有M条边(N≤10000,M≤50000)。求一共有多少个点,满足这样的条件:所有其它的点都可以到达这个点。
#include <stdio.h>
#include <iostream>
#include <vector>
#include <stack>
#include <string.h>
using namespace std;
const int N=10002;
const int M=50002;
int n,m;
int scc;//强连通分量
int index;//每个节点的访问次序编号 时间戳
int cnt;//边的数量
int dfn[N];//标记结点i的时间戳
int low[N];//记录节点u或u的子树中的所有节点的最小标号
int belong[N];//属于哪个分支
bool instack[N];//是否在栈中
int num[N];//记录一个强连通分量中结点的个数
int top;
int out[N];//出度
vector<int >p[N];
stack <int>s;
void tarjan(int u)
{
dfn[u]=low[u]=++index;
s.push(u);
instack[u]=true;
for (int j=0;j<p[u].size();j++)
{
int v=p[u][j];
if(dfn[v]==0)//未曾访问过
{
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++;
while(1)
{
int tmp=s.top();
s.pop();
instack[tmp]=0;
belong[tmp]=scc;
num[scc]++;
if(tmp==u)
break;
}
}
}
void solve()
{
scc=top=index=0;
int outnum;
memset(num,0,sizeof(num));
memset(dfn,0,sizeof(dfn));
for (int i=1;i<=n;i++)
{
if (!dfn[i])
tarjan(i);
}
memset(out,0,sizeof(out));
for (int i=1;i<=n;i++)
{
for(int j=0;j<p[i].size();j++)
{
int u=belong[i];
int v=belong[p[i][j]];
if(u!=v)
{
out[u]=1;
}
}
}
outnum=0;
int aug;
for(int i=1;i<=scc;i++)
{
if(!out[i])
{
outnum++;
aug=i;
}
}
if(outnum==1)
{
printf("%d\n",num[aug]);
}
else
{
puts("0");
}
}
int main()
{
while (scanf("%d%d",&n,&m)!=EOF)
{
cnt=0;
for (int i=1;i<=m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
p[a].push_back(b);
}
solve();
}
}