[HAOI2006]受欢迎的牛

首先我们要理解题意(一开始没想清楚)  后面才想明白

以下3点很重要!!!

1,如果明星牛羡慕其它牛,那么被它羡慕的牛也一定会羡慕它,然后构成一个环,所以我们可以考虑tarjan缩点

2,缩点以后出度为0的即为明星牛,反之出度不为0的肯定不是明星牛,因为to[x]不羡慕x

3,如果缩点后不止一个点出度为0的话就没有明星牛,因为这n个出度为0的点不能相互羡慕

搞懂了以上三点思路就清晰了

tarjan缩点,tarjan的过程中要记下一个缩掉的环中点的个数

最后有明星牛就输出个数,没有就输出0


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <stack>
#define maxn 100001
using namespace std;
int n,m,next[maxn],to[maxn],st[maxn],low[maxn],dfn[maxn],scc[maxn],out[maxn],topt,num,ans,nn[maxn];
bool f[maxn];
void add(int x,int y)
{
    to[++topt]=y;
    next[topt]=st[x];
    st[x]=topt;
}
stack<int>s;
void tarjan(int x)
{
    dfn[x]=low[x]=++topt;
    f[x]=1; s.push(x); int p=st[x];
    while (p)
    {
        if (!dfn[to[p]]) {tarjan(to[p]); low[x]=min(low[x],low[to[p]]);}
         else if (f[to[p]]) low[x]=min(low[x],dfn[to[p]]);
        p=next[p];
    }
    if (dfn[x]==low[x])
    {
        num++;
        while (s.top()!=x)
        {
            f[s.top()]=1;
            scc[s.top()]=num;
            s.pop();
            nn[num]++;
        }
        f[s.top()]=1;
        scc[s.top()]=num;
        s.pop();
        nn[num]++;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++) {int xx,yy; scanf("%d%d",&xx,&yy); add(xx,yy);}
    topt=0;
    for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i);
    for (int i=1;i<=n;i++)
    {
        int p=st[i];
        while (p)
        {
            if (scc[i]!=scc[to[p]]) out[scc[i]]++;
            p=next[p];
        }
    }
    int judge=0;
    for (int i=1;i<=num;i++)if (out[i]==0) judge++,ans=nn[i];
    if (judge!=1) printf("0");else printf("%d",ans);
return 0;
}
  
  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值