[HAOI2006]受欢迎的牛

来源:互联网 发布:二次元动态壁纸软件 编辑:程序博客网 时间:2024/06/05 20:54

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

以下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 100001using 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;}


原创粉丝点击