算法讨论:这题陷阱比较多。首先,被所有牛欢迎,这说明所有的牛都要在一个连通图中,也就是将所给的边看成无向边的时候,所有点要在一个连通图中。这个我们用并查集来实现就可以了。强连通分量的求法就很简单了,正常的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.