题意:有n个牛,m个有向“仰慕”关系,关系可传递,求多少个牛被所有牛都“仰慕”
思路:显然被所有牛仰慕的牛群是一强连通分量
所以先把乱图缩点成有向无环图
对有向无环图有这个重要结论:
任何连通的图都至少有一个入度为0的点和至少有一个出度为0的点(也就是至少有一个最高强连通分量和一个最低强连通分量)
所以本题是找连通图的唯一的最低强连通分量,显然仅有一个出度为0的强连通分量即是解
Tarjan算法:
//832K 79MS #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int N= 1e4+5; const int M= 5e4+50; struct edge { int u,v; int next; }es[M]; int head[N]; int low[N],dfn[N],tmp[N]; int n,m; int col[N]; int sta[N]; int top; int scc_num; void tardfs(int u,int lay) { tmp[u]=1; low[u]=lay; dfn[u]=lay; sta[++top]=u; for(int i=head[u];~i;i=es[i].next) { int v=es[i].v; if(tmp[v]==0) tardfs(v,lay+1); if(tmp[v]==1) low[u]=min(low[u],low[v]); } if(dfn[u]==low[u]) { ++scc_num; while(1) { int x=sta[top]; low[x]=scc_num; tmp[x]=2; if(sta[top--]==u) break; } } } int tarjan() { for(int i=1;i<=n;i++) if(tmp[i]==0) tardfs(i,1); return scc_num; } void ini() { memset(head,-1,sizeof(head)); memset(tmp,0,sizeof(tmp)); memset(col,0,sizeof(col)); memset(low,0,sizeof(low)); top=0; scc_num=0; } int main() { while(~scanf("%d%d",&n,&m)) { ini(); for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); es[i].u=u; es[i].v=v; es[i].next=head[u]; head[u]=i; } int num=tarjan(); int cnt=0; for(int i=1;i<=m;i++) { if(low[es[i].u]==low[es[i].v]) continue; int u=es[i].u; col[low[u]] = 1; } int t,ans=0; for(int i=1;i<=num;i++) if(col[i]==0) cnt++,t=i; if(cnt!=1) puts("0"); else { for(int i=1;i<=n;i++) if(low[i]==t) ans++; printf("%d\n",ans); } } return 0; }
//856K 32MS C++ 1844B #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int N= 1e4+5; const int M= 5e4+50; struct edge { int u,v; int next; }es[M]; int head[N]; int dfn[N]; int n,m; int gro[N]; int col[N]; int sta1[N]; int sta2[N]; int tp1,tp2; int scc_num; void garbow(int u,int lay) { dfn[u]=lay; sta1[++tp1]=u; sta2[++tp2]=u; for(int i=head[u];~i;i=es[i].next) { int v=es[i].v; if(gro[v]) continue; if(!dfn[v]) garbow(v,lay+1); else while(dfn[sta1[tp1]]>dfn[v]) tp1--; } if(sta1[tp1]==u) { tp1--; scc_num++; while(1) { int v=sta2[tp2]; gro[v]=scc_num; if(sta2[tp2--]==u) break; } } } void ini() { memset(head,-1,sizeof(head)); memset(col,0,sizeof(col)); memset(gro,0,sizeof(gro)); tp1=tp2=scc_num=0; } int main() { while(~scanf("%d%d",&n,&m)) { ini(); for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); es[i].u=u; es[i].v=v; es[i].next=head[u]; head[u]=i; } for(int i=1;i<=n;i++) if(!dfn[i]) garbow(i,1); for(int i=1;i<=m;i++) { int u=es[i].u,v=es[i].v; if(gro[u]==gro[v]) continue; col[gro[u]]=1; } int cnt=0,t; for(int i=1;i<=scc_num;i++) if(col[i]==0) cnt++,t=i; if(cnt!=1) puts("0"); else { int ans=0; for(int i=1;i<=n;i++) if(gro[i]==t) ans++; printf("%d\n",ans); } } return 0; }