[poj2186]Popular Cows(targin缩点)
题意:求其他所有牛都认为其牛的牛的个数。
解题关键:targin算法模板题,缩点形成一棵树,并不一定是棵树,可能含有多个入度为0的点,寻找出度为0的点(缩点之后的点)的个数,如果个数大于0,则无解,否则输出该强连通分量内的个数。
注意targin算法的数组不需要memset。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 using namespace std; 8 typedef long long ll; 9 #define MAXN 10010 10 #define MAXM 100010 11 struct edge{ 12 int to,nxt; 13 }e[MAXM]; 14 int degree[MAXN]; 15 int head[MAXN],st[MAXN],dfn[MAXN],lowest[MAXN],belong[MAXN]; 16 bool inst[MAXN]; 17 int n,m,scnt,top,tot;//scnt从1开始 18 void init(){ 19 memset(head,-1,sizeof head); 20 memset(degree,0,sizeof degree); 21 scnt=top=tot=0; 22 } 23 24 void add_edge(int u, int v){ 25 e[tot].to=v; 26 e[tot].nxt=head[u]; 27 head[u]=tot++; 28 } 29 30 void Tarjan(int u){ 31 dfn[u]=lowest[u]=++tot; 32 inst[u]=1; 33 st[top++]=u; 34 for(int i=head[u];i!=-1;i=e[i].nxt){ 35 int v=e[i].to; 36 if(!dfn[v]){ 37 Tarjan(v); 38 lowest[u]=min(lowest[u],lowest[v]); 39 } 40 else if(inst[v]){ 41 lowest[u]=min(lowest[u],dfn[v]);//也可用lowest 42 } 43 } 44 if(dfn[u]==lowest[u]){ 45 scnt++; 46 int t; 47 do{ 48 t=st[--top]; 49 inst[t]=false; 50 belong[t]=scnt; 51 }while(t!=u); 52 } 53 } 54 55 inline int read(){ 56 char k=0;char ls;ls=getchar();for(;ls<'0'||ls>'9';k=ls,ls=getchar()); 57 int x=0;for(;ls>='0'&&ls<='9';ls=getchar())x=(x<<3)+(x<<1)+ls-'0'; 58 if(k=='-')x=0-x;return x; 59 } 60 61 62 void solve(){//缩点 63 for(int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i); 64 for(int i=1;i<=n;i++){ 65 for(int j=head[i];j!=-1;j=e[j].nxt){ 66 if(belong[i]!=belong[e[j].to]){ 67 degree[belong[i]]++; 68 } 69 } 70 } 71 int sum=0,x=0; 72 for(int i=1;i<=scnt;i++) if(!degree[i]) sum++,x=i;//记录索引 73 if(sum!=1){ 74 printf("0\n"); 75 return; 76 } 77 sum=0; 78 for(int i=1;i<=n;i++){ 79 if(belong[i]==x) sum++; 80 } 81 printf("%d\n",sum); 82 return; 83 } 84 85 int main(){ 86 int a,b; 87 while(scanf("%d%d",&n,&m)!=EOF){ 88 init(); 89 while(m--){ 90 a=read(),b=read(); 91 add_edge(a,b); 92 } 93 solve(); 94 } 95 return 0; 96 }