poj 2186 Popular Cows 强联通分量tarjan/Kosaraju

题目简述:n头奶牛,给出若干个欢迎关系a b,表示a欢迎b,欢迎关系是单向的,但是是可以传递的。另外每个奶牛都是欢迎他自己的。求出被所有的奶牛欢迎的奶牛的数目


解法:先跑一遍taijan或Kosaraju算法。那么出度为0的强连通分量代表的就是受其他奶牛欢迎的,但是如果出度为0的强连通分量的个数大于1.那么则无解。因为将至少有两个分量里的奶牛互相不喜欢。所以我们的算法就是如果出度为0的强连通分量的个数是1.那么我们算出这里面点的个数就是最后的答案。


代码(tarjan):

const
  maxn=10005;

var
  n,m,i,j,x,ans,sum,tot,d,u:longint;
  last,stack,dfn,low,rd,cd,belong:array[1..maxn] of longint;
  f:array[1..maxn] of boolean;
  next,y:array[1..maxn*5] of longint;

procedure init;
var
  i:longint;
begin
  tot:=0;
  sum:=0;
  d:=0;
  ans:=0;
  fillchar(dfn,sizeof(dfn),0);
  fillchar(low,sizeof(low),0);
  fillchar(rd,sizeof(rd),0);
  fillchar(cd,sizeof(cd),0);
  fillchar(f,sizeof(f),false);
  fillchar(last,sizeof(last),0);
  readln(n,m);
  for i:=1 to m do
  begin
    readln(x,y[i]);
    next[i]:=last[x];
    last[x]:=i;
  end;
end;

function min(x,y:longint):longint;
begin
  if x<y then exit(x)
         else exit(y);
end;

procedure tarjan(x:longint);
var
  i:longint;
begin
  inc(d);
  dfn[x]:=d;
  low[x]:=d;
  inc(tot);
  stack[tot]:=x;
  f[x]:=true;
  i:=last[x];
  while i<>0 do
  begin
    if dfn[y[i]]=0
      then begin
             tarjan(y[i]);
             low[x]:=min(low[x],low[y[i]]);
           end
      else if f[y[i]] then low[x]:=min(low[x],dfn[y[i]]);
    i:=next[i];
  end;
  if low[x]=dfn[x] then
  begin
    inc(sum);
    repeat
      i:=stack[tot];
      dec(tot);
      f[i]:=false;
      belong[i]:=sum;
    until i=x;
  end;
end;

begin
  while not eof do
  begin
    init;
    for i:=1 to n do
      if dfn[i]=0 then tarjan(i);
    for i:=1 to n do
    begin
      j:=last[i];
      while j>0 do
      begin
        if belong[i]<>belong[y[j]] then
        begin
          inc(cd[belong[i]]);
          inc(rd[belong[y[j]]]);
        end;
        j:=next[j];
      end;
    end;
    j:=0;
    for i:=1 to sum do
      if cd[i]=0 then
      begin
        inc(j);
        u:=j;
      end;
    for i:=1 to n do
      if belong[i]=u then inc(ans);
    if j=1
      then writeln(ans)
      else writeln(0);
  end;
end.
</pre><pre code_snippet_id="1631039" snippet_file_name="blog_20160331_1_5072205" name="code" class="plain">
代码(Kosaraju):
var
  i,j,e,f1,e1,x,y,n,m,tot,u,ans:longint;
  v:array[1..10000] of boolean;
  last,f,belong,d:array[1..10000] of longint;
  side:array[1..100000] of record
    x,y,next:longint;
  end;


procedure add(x,y:longint);
begin
  inc(e);
  side[e].x:=x;
  side[e].y:=y;
  side[e].next:=last[x];
  last[x]:=e;
end;


procedure dfs(x:longint);
var
  i:longint;
begin
  v[x]:=false;
  i:=last[x];
  while i>0 do
    with side[i] do
    begin
      if v[y] then dfs(y);
      i:=next;
    end;
  if tot=0
    then begin
           inc(f1);
           f[f1]:=x;
         end
    else belong[x]:=tot;
end;


begin
  readln(n,m);
  for i:=1 to m do
  begin
    readln(x,y);
    add(x,y);
  end;
  fillchar(v,sizeof(v),true);
  for i:=1 to n do
    if v[i] then dfs(i);
  e1:=e;
  fillchar(v,sizeof(v),true);
  fillchar(last,sizeof(last),0);
  for i:=1 to e do
    add(side[i].y,side[i].x);
  for i:=n downto 1 do
    if v[f[i]] then
    begin
      inc(tot);
      dfs(f[i]);
    end;
  for i:=1 to e1 do
    with side[i] do
      if belong[x]<>belong[y] then inc(d[belong[x]]);
  j:=0;
  for i:=1 to tot do
    if d[i]=0 then
    begin
      inc(j);
      u:=i;
    end;
  for i:=1 to n do
    if belong[i]=u then inc(ans);
  if j>1
    then writeln(0)
    else writeln(ans);
end.



你可能感兴趣的:(poj 2186 Popular Cows 强联通分量tarjan/Kosaraju)