算法讨论:这题陷阱比较多。首先,被所有牛欢迎,这说明所有的牛都要在一个连通图中,也就是将所给的边看成无向边的时候,所有点要在一个连通图中。这个我们用并查集来实现就可以了。强连通分量的求法就很简单了,正常的Tarjan就好了。求完强连通分量之后重新建图,找出新图上出度为0的点,那么在原图上在这个强连通分量中的点的个数就是答案。
我的代码:
program popular;//By_Thispoet const maxn=10005; var i,j,k,m,n,p,q,total,time,size :longint; pr,la,ot,pre,other,last :array[0..maxn*5]of longint; stack,father :array[0..maxn]of longint; color,dfn,low,num :array[0..maxn]of longint; outo :array[0..maxn]of longint; function min(i,j:longint):longint; begin if i<j then exit(i);exit(j); end; function root(i:longint):longint; begin if father[i]=i then exit(i); father[i]:=root(father[i]); exit(father[i]); end; procedure union(i,j:longint); var x,y:longint; begin x:=root(i);y:=root(j); father[x]:=y; end; procedure deal(i:longint); begin inc(total); while stack[size]<>i do begin color[stack[size]]:=total; inc(num[total]); dec(size); end; color[i]:=total; inc(num[total]); dec(size); end; procedure tarjan(i:longint); var j,k:longint; begin inc(time); dfn[i]:=time;low[i]:=time; inc(size);stack[size]:=i; j:=la[i]; while j<>0 do begin k:=ot[j]; if dfn[k]<>-1 then low[i]:=min(low[i],dfn[k]) else begin tarjan(k); low[i]:=min(low[i],low[k]); end; j:=pr[j]; end; if low[i]=dfn[i] then deal(i); end; procedure prepare; begin k:=0; for i:=1 to n do begin j:=la[i];p:=color[i]; while j<>0 do begin q:=color[ot[j]]; if p<>q then inc(outo[p]); j:=pr[j]; end; end; end; begin readln(n,m); fillchar(num,sizeof(num),0); fillchar(la,sizeof(la),0); for i:=1 to n do father[i]:=i; for i:=1 to m do begin readln(p,q); union(p,q); inc(k);pr[k]:=la[p];la[p]:=k;ot[k]:=q; end; for i:=1 to n do if root(i)<>root(1) then begin writeln(0); halt; end; fillchar(dfn,sizeof(dfn),255); for i:=1 to n do if dfn[i]=-1 then tarjan(i); prepare; p:=0;q:=0; for i:=1 to total do if outo[i]=0 then begin inc(p); q:=i; end; if p=1 then writeln(num[q]) else writeln(0); end.