poj 2186 Popular Cows

/*
Tanjar缩点后 记好每个点属于第几个强联通分量
然后维护nu数组表示每个强联通分量的出度为几(枚举割边) 
只要某个强联通分量有出度而没有入度 说明并不是多有牛都认为这里面的牛牛 
最后找nu为零的唯一一个强联通分量
如果有好几个nu为零的  依旧没有符合条件的牛 即图并不连通 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 50010
using namespace std;
int n,m,num,head[maxn],dfn[maxn],low[maxn],si,anss,nu[maxn];
int stack[maxn],top,f[maxn],tim,sum,belong[maxn],ans[maxn];
struct node
{
    int u,v,pre;
}e[maxn];
int init()
{
    int x=0;char s;s=getchar();
    while(s<'0'||s>'9')s=getchar();
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    return x;
}
void Add(int from,int to)
{
    num++;
    e[num].u=from;
    e[num].v=to;
    e[num].pre=head[from];
    head[from]=num;
}
void Tanjar(int s)//tarjan缩点 
{
    dfn[s]=low[s]=++tim;//time为关键字... 
    stack[++top]=s;
    f[s]=1;
    for(int i=head[s];i;i=e[i].pre)
      {
          if(dfn[e[i].v]==0)//还没有被访问过 即白点 
            {
                Tanjar(e[i].v);
                low[s]=min(low[s],low[e[i].v]);//可以用 low[e[i].v] 更新 low[s](白色路径定理) 
          }
        else if(f[e[i].v])//已经入栈 即是一条后向边用 dfn[e[i].v] 更新 low[s]
        low[s]=min(low[s],dfn[e[i].v]);
      }
    if(dfn[s]==low[s])
      {
          sum++;
          while(stack[top]!=s)
          {
            ans[sum]++;f[stack[top]]=0;
            belong[stack[top]]=sum;top--;
          }
        ans[sum]++;f[stack[top]]=0;
        belong[stack[top]]=sum;top--;
      }
}
int main()
{
    n=init();m=init();
    int x,y;
    for(int i=1;i<=m;i++)
      {
          x=init();y=init();
          Add(x,y);
      }
    for(int i=1;i<=n;i++)
      if(dfn[i]==0)
        Tanjar(i);
    for(int i=1;i<=n;i++)
      for(int j=head[i];j;j=e[j].pre)
        if(belong[i]!=belong[e[j].v])
          nu[belong[i]]++;//统计出度 
    for(int i=1;i<=sum;i++)
      if(nu[i]==0)
        {
          si++;
          anss=ans[i];
        }
    if(si==1)cout<<anss;
    else cout<<"0";
    return 0;
}
原文地址:https://www.cnblogs.com/yanlifneg/p/5487594.html