Poj2186 Popular Cows

Poj2186 Popular Cows
Description
Every cow’s dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is
popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow.

Input
* Line 1: Two space-separated integers, N and M
* Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.
Output
* Line 1: A single integer that is the number of cows who are considered popular by every other cow.
b
Sample Input
3 3
1 2
2 1
2 3

Sample Output
1

Hint
Cow 3 is the only cow of high popularity.

题目大意
N头奶牛(N≤10000)
M对关系(a , b),表示a认为b是受欢迎的
关系具有传递性,即若(a,b),(b,c)→(a,c)
询问有多少头奶牛是被其他所有奶牛认为是受欢迎的

强连通分量+缩环
把那些相互喜欢的牛看作一个点,然后做AOV网(类似)出度为零就只被别牛喜欢,出度为零的不止一个的话 ,它们必然相互不喜欢,则无解

#include<cstdio>
struct node{int v,first;}no[10010];
struct edge{int v,next;}e[50010];
int en=0;
void addedge(int a,int b){en++;e[en].v=b;e[en].next=no[a].first;no[a].first=en;}//邻接表 
int low[10010],st[10010],dfn[10010],index=1,top=1,vi,in_stack[10010];
//low表示该点所在的强连通子图所在搜索子树的根节点的Dfn值      dfn表示递归中发现该节点的时间  时间则用每递归一次就加一的index表示 
//st 表示栈  top栈顶in_stack记录一个点是否在栈中 
int scc[10010],cscc=1,outger[10010];
//记录节点在那个强连通分量中   cscc记录强连通分量的个数和作为每一个强连通分量的标记   outger每一个强连通分量的出度 
void tarjan(int rt)
{
    low[rt]=dfn[rt]=index++;//刚发现该节点是它自身即为根节点 low等于dfn  index加一表时间 
    in_stack[rt]=1;st[top++]=rt;//入栈  做标记 
    for(int i=no[rt].first;i;i=e[i].next)//遍历从它出去的每一个点 
    {
        vi=e[i].v;//当前遍历到的点 
        if(!dfn[vi]){tarjan(vi);low[rt]=low[rt]<low[vi]?low[rt]:low[vi];}//如果这个点以前还没有发现 就把它递归去  
        else if(in_stack[vi]==1){low[rt]=low[rt]<dfn[vi]?low[rt]:dfn[vi];}//如果它就在栈里 遇上环了 开心吗? 
       // 强连通分量是由若干个环组成的。所以,当有环形成时(也就是搜索的下一个点已在栈中),我们将这一条路径的low值统一,
       //即这条路径上的点属于同一个强连通分量。如果遍历完整个搜索树后某个点的dfn值等于low值,
       //则它是该搜索子树的根。这时,它以上(包括它自己)一直到栈顶的所有元素组成一个强连通分量。

    }
    if(low[rt]==dfn[rt])//同上所诉如果low等于dfn 此处应有强连通分量 可能是一个环也可能是一个点 
    {
        do{vi=st[--top];in_stack[vi]=0;scc[vi]=cscc;}while(rt!=vi);//把它们出栈  标记为0,记录同一个强连通分量的标号cscc 
        cscc++;//每记录一个强连通分量 就自行加一 你值得 拥有 
    }
}
void out(int n)
{
    for(int i=1;i<=n;i++)//每个点遍历一边 
    {
        for(int j=no[i].first;j;j=e[j].next)//每个点相连的边遍历一边 
        {
            if(scc[i]!=scc[e[j].v])outger[scc[i]]++;//如果它们不在同一个强连通分量中 ,化分量为点,记录每个分量的出度 
        }
    }
    int minqq=0,minw,t=0;
    for(int i=1;i<cscc;i++){if(0==outger[i]){minqq++;minw=i;}}//找到出度为零的强连通分量记录下来 
    for(int i=1;i<=n;i++)
    {
        if(scc[i]==minw)t++;//每个点遍历一便,如果标记等于找到的强连通分量的标号 就又找到了一个在其中的点 计数器加一 
    }
    if(minqq!=1)printf("NO");//如果不止一个出度为零 ,那它们相互不可达,无解 
    else    printf("%d\n",t);//输出计数器的数量,即有多少头牛 
}
int main()
{
    int a,b,n,m,i;
    scanf("%d %d",&n,&m);
    for(i=1;i<=m;i++)
    {
        scanf("%d%d",&a,&b);addedge(a,b);
    }
    for(i=1;i<=n;i++)if(!dfn[i])tarjan(i);//把点遍历一边 因为谁也不知道有多少个强连通分量 ,说不定有n个呢 
    out(n);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值