码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj1051 [HAOI2006]受欢迎的牛

时间:2017-09-04 20:40:39      阅读:127      评论:0      收藏:0      [点我收藏+]

标签:pre   gre   强连通   关系   ace   haoi2006   space   重复   names   

1051: [HAOI2006]受欢迎的牛

Time Limit: 10 Sec  Memory Limit: 162 MB

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
 
Tip:
  这题还是比较经典的tarjan缩点模板题;
  如果A认为B是受欢迎的,那么连A->B;
  将整个图缩点,变成了一个有向无环图;
  如果缩点后的图中点的出度=0的点数大于2个,则没有答案,没有任何一头奶牛能被所有奶牛认可;
                  1个,则答案即那个强连通分量里的点的数量;
 
Code
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#define MAXN 100008
using namespace std;
int n,m,hh[MAXN],head[MAXN],vet[MAXN],next[MAXN],tot,dfn[MAXN],low[MAXN],color[MAXN];
int tot1,num[MAXN],str[MAXN],cnt,boo[MAXN],top,belong[MAXN],tim;

void add(int x,int y){
    tot++;
    hh[tot]=x;
    next[tot]=head[x];
    head[x]=tot;
    vet[tot]=y;
}

void tarjan(int u){
    tim++;
    dfn[u]=low[u]=tim;
    boo[u]=color[u]=1;
    str[++top]=u;
    for(int i=head[u];i!=-1;i=next[i]){
        int y=vet[i];
        if(color[y]==0){
            tarjan(y);
            low[u]=min(low[u],low[y]);
        }else{
            if(boo[y])
                low[u]=min(low[u],dfn[y]);
        }
    }
    color[u]=2;
    if(dfn[u]==low[u]){
        cnt++;
        int v;
        do{
            v=str[top--];
            belong[v]=cnt;
            boo[v]=1;
        }while(v!=u&&top>0);
    }
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        head[i]=-1;
    for(int i=1;i<=m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i]){
            tarjan(i);
        }
    for(int i=1;i<=tot;i++){
        if(belong[hh[i]]!=belong[vet[i]]){
            num[belong[hh[i]]]++;
        }
    }
    int ans=0,flag;
    for(int i=1;i<=cnt;i++){
        if(num[i]==0){
            ans++;
            if(ans>1){
                printf("0");
                return 0;
            }
            flag=i;
        }
    }
    if(ans==1){
        int res=0;
        for(int i=1;i<=n;i++)
            if(belong[i]==flag)
                res++;
        printf("%d",res);
    }else{
        printf("0");
    }
}

 

  

bzoj1051 [HAOI2006]受欢迎的牛

标签:pre   gre   强连通   关系   ace   haoi2006   space   重复   names   

原文地址:http://www.cnblogs.com/WQHui/p/7475466.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!