poj 2186 Popular Cows

Popular Cows
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 31157 Accepted: 12647

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. 

Sample Input

3 3
1 2
2 1
2 3

Sample Output

1

Hint

Cow 3 is the only cow of high popularity. 

Source

提示

题意:

有n(1<=n<=10000)头牛,有m(1<=m<=50000)条信息,每条信息给予A牛认为B牛比自己更受欢迎,并且欢迎性是可传递的,A牛认为B牛比自己更受欢迎,B牛认为C牛比自己更受欢迎,那么A牛也同时认为C牛比自己更受欢迎,请求出有几只牛是公认最受欢迎的,条件不足输出'0'。

思路:

n,m比较大,爆搜势必TLE,所以利用Tarjan缩点求出强连通分量。

这些缩点就会组成一个有向无环树,那么只有一个根节点(即出度为0的点),如果有多个说明条件不足输出0。

满足条件输出该强连通分量上点的数量。

举个栗子:


由此看6是最受欢迎的,输出1。

如果再加一个点,且与6建立双向边,即6->7,7->6,那么就输出2。因为1~5认为6受欢迎,6认为7比自己更受欢迎,7也认为6比自己更受欢迎,它们两构成了一个强连通分量,那么就输出2。

示例程序

Source Code

Problem: 2186		Code Length: 2319B
Memory: 1016K		Time: 79MS
Language: GCC		Result: Accepted
#include <stdio.h>
#include <string.h>
struct
{
    int v,next;
}w[50001];
int h[10001],vis[10001],dfn[10001],low[10001],id[10001],degree[10001],deep,stack[50001],top,numw,count;
void insert(int u,int v)
{
    w[numw].v=v;
    w[numw].next=h[u];
    h[u]=numw;
    numw++;
}
void tarjan(int t)
{
    int i;
    dfn[t]=deep;
    low[t]=deep;
    vis[t]=1;
    stack[top]=t;
    top++;
    deep++;
    for(i=h[t];i!=-1;i=w[i].next)
    {
        if(dfn[w[i].v]==-1)
        {
            tarjan(w[i].v);
            if(low[t]>low[w[i].v])
            {
                low[t]=low[w[i].v];
            }
        }
        else if(vis[w[i].v]==1&&low[t]>dfn[w[i].v])
        {
            low[t]=dfn[w[i].v];
        }
    }
    if(low[t]==dfn[t])
    {
        count++;
        do
        {
            top--;
            t=stack[top];
            vis[t]=0;
            id[t]=count;				//为每个分量涂上色
        }while(low[t]!=dfn[t]);
    }
}
int main()
{
    int n,m,i,i1,pos,u,v,num;
    memset(h,-1,sizeof(h));
    memset(dfn,-1,sizeof(dfn));
    memset(low,-1,sizeof(low));
    memset(id,0,sizeof(id));
    memset(degree,0,sizeof(degree));
    memset(vis,0,sizeof(vis));
    pos=-1;
    deep=0;
    top=0;
    numw=0;
    count=0;
    num=0;
    scanf("%d %d",&n,&m);
    for(i=1;m>=i;i++)
    {
        scanf("%d %d",&u,&v);
        insert(u-1,v-1);
    }
    for(i=0;n>i;i++)
    {
        if(dfn[i]==-1)
        {
            tarjan(i);
        }
    }
    if(count==1)				//只有一个分量就不要再去看出度数了
    {
        printf("%d\n",n);
    }
    else
    {
        for(i=0;n>i;i++)
        {
            for(i1=h[i];i1!=-1;i1=w[i1].next)
            {
                if(id[i]!=id[w[i1].v])
                {
                    degree[id[i]]++;		//该连通分量出度加1
                }
            }
        }
        for(i=1;count>=i;i++)
        {
            if(degree[i]==0)
            {
                if(pos==-1)
                {
                    pos=i;
                }
                else				//出度为0的分量不止一个
                {
                    break;
                }
            }
        }
        if(count>=i)				//条件不成立
        {
            printf("0");
        }
        else
        {
            for(i=0;n>i;i++)
            {
                if(pos==id[i])				//连通分量度数为0的点数量
                {
                    num++;
                }
            }
            printf("%d",num);
        }
   }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值