bzoj 1051 缩点重构图

61 篇文章 0 订阅
11 篇文章 0 订阅

题意:给出m个数对(a,b)  表示a牛认为b牛受欢迎,如果a牛认为b牛受欢迎,b牛认为c牛受欢迎,则a牛也认为c牛受欢迎。找到被所有牛认为是受欢迎的牛的个数(自己不用认为自己受欢迎= =)

我们很容易发现“认为受欢迎”是具有传递性

那么,对于a牛认为b牛受欢迎我们就建一条a指向b的有向边

然后我们发现,对于每一个强连通分量,他们是互相认为受欢迎的=。=

那么我们所点重新构图后就形成了一个DAG

重新构图后,

如果有且仅有一个“点”的出度为0那么答案就是这个“点”的size

否则输出0

var
    n,m,a,b,l,time,top,t,ans:longint;
    last                    :array[0..10010] of longint;
    size,chu                :array[0..20010] of longint;
    dfn,low,z,belong        :array[0..10010] of longint;
    vis                     :array[0..20010] of boolean;
    i                       :longint;
    pre,other               :array[0..50010] of longint;

function min(a,b:longint):longint;
begin
   if a<b then exit(a) else exit(b);
end;

procedure connect(x,y:longint);
begin
   inc(l);
   pre[l]:=last[x];
   last[x]:=l;
   other[l]:=y;
end;

procedure dfs(x:longint);
var
    p,q,cur:longint;
begin
   inc(time);
   low[x]:=time;
   dfn[x]:=time;
   inc(top);
   z[top]:=x;
   vis[x]:=true;
   //
   q:=last[x];
   while (q<>0) do
   begin
      p:=other[q];
      if dfn[p]=0 then
      begin
         dfs(p);
         low[x]:=min(low[x],low[p]);
      end else
      if vis[p] then low[x]:=min(low[x],dfn[p]);
      q:=pre[q];
   end;
   //
   if (low[x]=dfn[x]) then
   begin
      cur:=-1;
      while (cur<>x) do
      begin
         cur:=z[top];
         dec(top);
         vis[cur]:=false;
         belong[cur]:=x+n;
         inc(size[belong[cur]]);
      end;
   end;
end;

procedure rebuild;
var
    p,q:longint;
    i:longint;
begin
   for i:=1 to n do
   begin
      q:=last[i];
      while (q<>0) do
      begin
         p:=other[q];
         if (belong[i]<>belong[p]) then inc(chu[belong[i]]);
         q:=pre[q];
      end;
   end;
end;

begin
   read(n,m);
   for i:=1 to m do
   begin
      read(a,b);
      connect(a,b);
   end;
   //
   for i:=1 to n do if dfn[i]=0 then dfs(i);
   //
   rebuild;
   t:=0;
   for i:=n+1 to n*2 do vis[i]:=false;
   for i:=1 to n do
    if (chu[belong[i]]=0) and not vis[belong[i]] then
    begin
       inc(t);
       ans:=size[belong[i]];
       vis[belong[i]]:=true;
    end;
   //
   if (t=1) then writeln(ans) else writeln(0); 

end.
——by Eirlys



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值