bzoj1051[HAOI2006]受欢迎的牛

bzoj1051[HAOI2006]受欢迎的牛

题意:

有N头牛,给M对整数(A,B),表示牛A认为牛B受欢迎,这种关系具有传递性。求出有多少头牛被所有的牛认为是受欢迎的。N≤10000

题解:

因为求的是被所有牛认同的牛,如果该牛不认同任何牛,那么这头牛出度为0,且出度为0的牛有且只有一个否则不存在所求牛。如果这头牛认同别的牛,那么就要求这两头牛互相认同。同时两头牛都是所求牛。因此做个tarjan缩点,缩点后若出度为0的点有多个则没有所求牛,若只有一个那么这个点所表示强连通块里的所有点都是所求牛。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <stack>
 5 #define inc(i,j,k) for(int i=j;i<=k;i++)
 6 using namespace std;
 7 
 8 struct e{int f,t,n;}; e es[60000]; int g[20000],ess;
 9 void pe(int f,int t){es[++ess]=(e){f,t,g[f]}; g[f]=ess;}
10 int bel[20000],cnt[20000],n,m,sz[20000],tot,low[20000],pre[20000],tim; bool vis[20000],ins[20000];
11 stack <int> s;
12 void dfs(int x){
13     vis[x]=ins[x]=1; s.push(x); low[x]=pre[x]=++tim;
14     for(int i=g[x];i;i=es[i].n)
15         if(!vis[es[i].t])dfs(es[i].t),low[x]=min(low[x],low[es[i].t]);
16         else if(ins[es[i].t])low[x]=min(low[x],pre[es[i].t]);
17     if(low[x]==pre[x]){
18         tot++;
19         while(!s.empty()){
20             int now=s.top(); s.pop(); bel[now]=tot; sz[tot]++; ins[now]=0; if(now==x)break;
21         }
22     }
23 }
24 void tarjan(){
25     while(!s.empty())s.pop(); memset(vis,0,sizeof(vis)); memset(ins,0,sizeof(ins)); memset(sz,0,sizeof(sz));
26     tot=tim=0; inc(i,1,n)if(! vis[i])dfs(i);
27 }
28 void solve(){
29     memset(cnt,0,sizeof(cnt)); inc(i,1,ess)if(bel[es[i].f]!=bel[es[i].t])cnt[bel[es[i].f]]++; int a=0;
30     inc(i,1,tot){
31         if(cnt[i]==0&&a!=0){printf("0\n"); return;}
32         if(cnt[i]==0)a=i;
33     }
34     printf("%d\n",sz[a]);
35 }
36 int main(){
37     scanf("%d%d",&n,&m); ess=0; memset(g,0,sizeof(g));
38     inc(i,1,m){int a,b; scanf("%d%d",&a,&b); pe(a,b);}
39     tarjan(); solve();
40     return 0;
41 }

 

20160517

posted @ 2016-08-03 13:54  YuanZiming  阅读(...)  评论(... 编辑 收藏