大意:给定n头牛,牛之间为有向的羡慕关系并且关系可以传递,问最后有多少个牛被所有的牛羡慕。
思路:羡慕的关系链或者环都可以进行缩点,使得图抽象DAG(有向无环图)。每个节点就是一个联通分量,我们统计每个联通分量的出度,当出度为0的连通分量数目大于1时就表明不是所以牛都羡慕其中的一头牛,结果为0。否则,我们直接找到最后缩点后的图中有多少个点就是最终的结果。
#include<map> #include<queue> #include<cmath> #include<cstdio> #include<stack> #include<iostream> #include<cstring> #include<algorithm> #define LL int #define inf 0x3f3f3f3f #define eps 1e-8 #include<vector> #define ls l,mid,rt<<1 #define rs mid+1,r,rt<<1|1 using namespace std; const int Ma = 1000005; int head[Ma],dfn[Ma],num[Ma],du[Ma],stk[Ma],vis[Ma],low[Ma]; int cnt,top,time,css; struct node{ int to,next; }q[Ma]; void bu(int a,int b){ q[cnt].to = b; q[cnt].next = head[a]; head[a] = cnt++; } void init(){ time = 1; css = top = cnt = 0; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(vis,0,sizeof(vis)); memset(head,-1,sizeof(head)); memset(num,0,sizeof(num)); memset(du,0,sizeof(du)); } void Tarjan(int u){ low[u] = dfn[u] = time++; vis[u] = 1; stk[top++] = u; for(int i = head[u]; ~i ; i = q[i].next){ int v = q[i].to; if(!dfn[v]){ Tarjan(v); low[u] = min(low[u],low[v]); } else if(vis[v]) low[u] = min(low[u],dfn[v]); } if(low[u] == dfn[u]){//找到极大联通分量 css++; while(top > 0&&stk[top] != u){ top --; vis[stk[top] ] = 2; num[stk[top] ] = css; } } } int main(){ int n,m,i,j,k,a,b; while(~scanf("%d%d",&n,&m)){ init(); for(i = 0;i < m;++ i){ scanf("%d%d",&a,&b); bu(a,b); } for(i = 1;i <= n;++ i){ if(!dfn[i]) Tarjan(i); } for(i = 1;i <= n;++ i){ for(j = head[i]; ~j ; j = q[j].next){ if(num[i]!=num[q[j].to ]) du[num[i] ]++; } } int sum = 0,tmp; for(i = 1;i <= css;++ i){ if(!du[i]){ sum++; tmp = i; } } if(sum==1){ sum = 0; for(i = 1;i <= n;++ i) if(num[i] == tmp) sum++; printf("%d\n",sum); } else printf("0\n"); } return 0; }