bzoj1051受欢迎的牛(Tarjan)

1051: [HAOI2006]受欢迎的牛

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 4776  Solved: 2542

Description

  每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这
种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头
牛被所有的牛认为是受欢迎的。

Input

  第一行两个数N,M。 接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复,即有可
能出现多个A,B)

Output

  一个数,即有多少头牛被所有的牛认为是受欢迎的。

Sample Input

3 3
1 2
2 1
2 3

Sample Output

1

HINT

 

100%的数据N<=10000,M<=50000
/*这是一个缩点Tarjan求环的裸题 */ 
#include<iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const int Maxn = 10005;
const int Maxm = 100005;
struct node
{
    int to,next;
} edge[Maxm];
int n,m,head[Maxn],dfn[Maxn],low[Maxn],stack1[Maxn],num[Maxn],du[Maxn],vis[Maxn],cnt,tt,top,cut;

void init()
{
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(head,-1,sizeof(head));
    memset(vis,0,sizeof(vis));
    memset(num,0,sizeof(num));
    memset(du,0,sizeof(du));
}

void addedge(int u,int v)
{
    edge[cnt].to=v;
    edge[cnt].next=head[u];
    head[u]=cnt;
    cnt++;
}

void Tarjan(int u,int fa)
{
    dfn[u]=tt;
    low[u]=tt;
    tt++;
    vis[u]=1;
    stack1[top]=u;
    top++;
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v=edge[i].to;
        if(!vis[v])
        {
            Tarjan(v,u);
            low[u]=min(low[u],low[v]);
        }
        else if(vis[v])
        {
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(low[u]==dfn[u])
    {
        cut++;
        while(top>0&&stack1[top]!=u)
        {
            top--;
            vis[stack1[top]]=2;
            num[stack1[top]]=cut;
        }
    }
}

int main()
{
    int u,v;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        for(int i=0; i<m; i++)
        {
            scanf("%d%d",&u,&v);
            addedge(u,v);
        }
        for(int i=1; i<=n; i++)
        {
            if(!vis[i])
            {
                Tarjan(i,0);
            }
        }
        for(int i=1; i<=n; i++)
        {
            for(int j=head[i]; j!=-1; j=edge[j].next)
            {
                if(num[i]!=num[edge[j].to])
                {
                    du[num[i]]++;
                }
            }
        }
        int sum=0,x;
        for(int i=1; i<=cut; i++)
        {
            if(!du[i])
            {
                sum++;
                x=i;
            }
        }
        if(sum==1)
        {
            sum=0;
            for(int i=1; i<=n; i++)
            {
                if(num[i]==x)
                {
                    sum++;
                }
            }
            printf("%d\n",sum);
        }
    }
    return 0;
}
心若向阳,无谓悲伤

 

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=10005,M=50005;
int n=0,m=0;
int head[N],to[M],next[M],edge=0;
int dfn[N],inS[N],idx=1,low[N];
int stk[N],top=0;
int comp[N],n2=0,cnt[N];
int in[N];
int head2[N],to2[M],next2[M],edge2=0;
int q[N*233],front=0,back=0,vis[N];
inline void addEdge(int u,int v) {
    to[edge]=v,next[edge]=head[u],head[u]=edge++;
}
void tarjan(int x) {
    dfn[x]=low[x]=idx++;
    stk[top++]=x;
    inS[x]=1;
    for (int e=head[x];~e;e=next[e]) {
        int& v=to[e];
        if (!dfn[v]) {
            tarjan(v);
            low[x]=min(low[x],low[v]);
        } else if (inS[x]) 
            low[x]=min(low[x],dfn[v]);
    }
    if (dfn[x]==low[x]) {
        ++n2;
        int u=0;
        do {
            u=stk[--top];
            comp[u]=n2;
            inS[u]=0;
            ++cnt[n2];
        } while (u!=x);
    }
}
inline void addEdge2(int u,int v) {
    ++in[v];
    to2[edge2]=v,next2[edge2]=head2[u],head2[u]=edge2++;
}
inline void build() {
    for (int i=1;i<=n;++i)
        for (int e=head[i];~e;e=next[e]) {
            int &u=comp[i],&v=comp[to[e]];
            if (u!=v)
                addEdge2(v,u);
        }
}
inline int bfs(int s) {
    front=back=0;
    memset(vis,0,sizeof(vis));
    q[back++]=s;
    vis[s]=1;
    while (front<back) {
        int x=q[front++];
        for (int e=head2[x];~e;e=next2[e]) {
            int& v=to2[e];
            if (!vis[v]) {
                q[back++]=v;
                vis[v]=1;
            }
        }
    }
    for (int i=1;i<=n2;++i)
        if (!vis[i])
            return 0;
    return 1;
}
int main(void) {
    memset(head,-1,sizeof(head));
    scanf("%d %d",&n,&m);
    while (m--) {
        int u=0,v=0;
        scanf("%d %d",&u,&v);
        addEdge(u,v);
    }        
    for (int i=1;i<=n;++i)
        if (!dfn[i])
            tarjan(i);
    //建缩点以后的反图 就所有入度为0的点bfs
     memset(head2,-1,sizeof(head2));
     build();
     int ans=0;
     for (int i=1;i<=n2;++i)
         if (!in[i])
             if (bfs(i))
                 ans+=cnt[i];
    printf("%d\n",ans);
    return 0;
} 
上个代码在洛谷不过,求大神指点

 

posted @ 2016-12-11 15:36  安月冷  阅读(...)  评论(... 编辑 收藏