【强连通分量】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; }

 

你可能感兴趣的:(ZOJ)