首页 > 代码库 > 【强连通分量】bzoj 1051 受欢迎的牛

【强连通分量】bzoj 1051 受欢迎的牛

1051: [HAOI2006]受欢迎的牛

时间限制: 10 Sec  内存限制: 162 MB
提交: 2150  解决: 1129
[提交][]

题目描述

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

输入

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

输出

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

样例输入

3 3
1 2
2 1
2 3

样例输出

1

提示

100%的数据N<=10000,M<=50000

来源

还是强连通分量的题

还是出度为0的缩点是所有牛都欢迎的

开始看成受欢迎的牛群有多少

然后就傻×的想有多个牛群怎么都会有所有的牛认为是受欢迎的

然后就看题解 =.= 我是渣

哎-----

# include<cstdio># include<cstring># include<stack># include<algorithm># include<iostream>using namespace std;const int N=10000+10;const int M=50000+10;stack<int>S;int n,m,ecnt,scc_cnt,dfs_clock,tot,out_degree,cur;int fist[N],next[M],v[M],pre[N],low[N],scc_no[N],size[N],out[N];void built(int a,int b){    ++ecnt;    v[ecnt]=b;    next[ecnt]=fist[a];    fist[a]=ecnt;}int check(int a,int b){    for(int e=fist[a];e!=-1;e=next[e])    if(v[e]==b)return 0;    return 1;}void init(){    int a,b;    memset(fist,-1,sizeof(fist));    scanf("%d%d",&n,&m);    for(int i=1;i<=m;i++){        scanf("%d%d",&a,&b);    //    if(check(a,b))        built(a,b);    }}int dfs(int u){    int lowu=pre[u]=++dfs_clock;    S.push(u);    for(int e=fist[u];e!=-1;e=next[e])    if(!pre[v[e]])    lowu=min(lowu,dfs(v[e]));    else if(!scc_no[v[e]])    lowu=min(lowu,pre[v[e]]);    low[u]=lowu;    if(low[u]==pre[u]){        scc_cnt++;        for(;;){            int x=S.top();S.pop();            scc_no[x]=scc_cnt;            if(x==u)break;        }    }    return low[u];}void find_scc(){    memset(pre,0,sizeof(pre));    memset(low,0,sizeof(low));    for(int i=1;i<=n;i++)    if(!pre[i])dfs(i);}void work(){    for(int i=1;i<=n;i++)for(int e=fist[i];e!=-1;e=next[e])    if(scc_no[i]!=scc_no[v[e]])out[scc_no[i]]++;    for(int i=1;i<=scc_cnt;i++)if(out[i]==0)out_degree=i;    for(int i=1;i<=n;i++)if(scc_no[i]==out_degree)tot++;    printf("%d",tot);}int main(){    init();    find_scc();    work();    return 0;}

 

【强连通分量】bzoj 1051 受欢迎的牛