#include<stdio.h> #include<string.h> #define adj 10010 #define edg 50010 struct node { int v; int next; }; node edge[edg]; node edge1[edg]; int low[adj],dfn[adj],Stack[adj]; int first[adj],first1[adj],fuck[adj]; bool ins[adj]; int n,m,temp,cnt,top,count; int cnt_size[adj],belong[adj],outdegree[adj]; void creat(int u,int v) { edge1[count].next=first1[u]; edge1[count].v=v; first1[u]=count++; } void tarjan(int u) { int i,v; dfn[u]=low[u]=++temp; Stack[top++]=u; ins[u]=true; for(i=first[u];i!=-1;i=edge[i].next) { v=edge[i].v; if(!dfn[v]) { tarjan(v); if(low[u]>low[v]) low[u]=low[v]; } else if(ins[v]) { if(low[u]>dfn[v]) low[u]=dfn[v]; } } if(dfn[u]==low[u]) { int j; do { top--; j=Stack[top]; ins[j]=false; cnt_size[cnt]++; belong[j]=cnt; }while(u!=j); cnt++; } } int main() { int i,j,k,v,sum,num; int e=0; scanf("%d%d",&n,&m); memset(first,-1,sizeof(first)); for(k=0;k<m;k++)//建立图 { scanf("%d%d",&i,&j); edge[e].v=j; edge[e].next=first[i]; first[i]=e; e++; } memset(dfn,0,sizeof(dfn)); memset(ins,false,sizeof(ins)); temp=cnt=top=0; memset(cnt_size,0,sizeof(cnt_size)); memset(low,0,sizeof(low)); for(i=1;i<=n;i++)//求强连通分量 { if(!dfn[i]) tarjan(i); } memset(first1,-1,sizeof(first1)); count=0; for(i=1;i<=n;i++)//重新构造图 { for(j=first[i];j!=-1;j=edge[j].next) { v=edge[j].v; if(belong[i]!=belong[v]) creat(belong[i],belong[v]); } } memset(outdegree,0,sizeof(outdegree)); for(i=0;i<cnt;i++)//求每个节点的出度 { for(j=first1[i];j!=-1;j=edge1[j].next) outdegree[i]++; } sum=num=0; for(i=0;i<cnt;i++) { if(outdegree[i]==0) //求节点为0的个数 { sum=cnt_size[i]; num++; } } if(num==1) printf("%d\n",sum); else printf("0\n"); return 0; }
题意:有N只牛,输入a,b的话,则说明b关注a,而且关注有传递性。例如c关注b,且b关注a,则c也关注a。题目问有多少只奶牛能被其他所有的奶牛关注。
把题目的模型转换:N个顶点的有向图,有M条边。求一共有多少个点,满足这样的条件:所有其它的点都可以到达这个点。这个点满足条件的充要条件是:这个点是树中唯一的出度为0的点。
先求强连通分量,然后可以把强连通分量缩成一个点,因为,在强连通分量中的任意两个点可以到达,所有的点具有相同的性质,即它们分别能到达的点集都是相同的,能够到达它们的点集也是相同的。然后就重新构图,缩点后的图是没有强连通分量的,否则,可将环上所有点也缩成一个点,与极大强联通分量矛盾。所以只要找出度为0的点,并且出度为0的点只有1个 ,如果出度为0的点有多个的话,问题则无解。