POJ2186 Popular Cows Tarjan 链接表 pascal解题报告

2186是我OI史上第一道Tarjan,之前看了很多的题解都是C或者C++的,让我一个学pascal的很难堪,做了一天之后AC,便想到写一篇pascal的解题报告。

题目的大意就是说有若干只奶牛,奶牛之间存在一种单向的羡慕之意,奶牛数为N(1<=n<=10000),羡慕之意有M(1<=M<=50000)条,让我们求出有多少头奶牛是被除自己以外的所有奶牛羡慕。

稍微画一下图就大概明白了要怎么写,其实就是给出一个有向图G,把图G的所有极大强连通分量求出来,然后进行缩点,形成一个无环图C,在这个无环图里,至少有一个是出度为0的点,若出度为0的点不止一个,那么就输出0(因为既然有多个出度为0的点,那么意味着没有一个点被其他所有点到达),否则输出出度为0的那个点是由原来多少个节点缩成。

可以看到题目的数据比较大,用矩阵需要一个10000*10000的数组,必定会爆空间(一开始做的时候用矩阵爆了好几次),用链接表只是50000+10000而已,数组只开10000和50000会WA,所以开大点

代码:

type
  rec=record
        next,t:longint;
      end;
var
  f,v:array[1..10010] of boolean;
  edge:array[1..50010] of rec;
  head,low,dfn,cd,sd,stack:array[1..10010] of longint;
  n,m,x,y,ans,deep,top,t,tmp,sum,i:longint;
  function min(a,b:integer):longint;
  begin
    if a<b then exit(a) else exit(b);
  end;
  procedure pop(k:longint);
  begin
    while stack[top+1]<>k do
    begin
      sd[stack[top]]:=ans;
      f[stack[top]]:=false;
      dec(top);
    end;
  end;
  procedure dfs(k:longint);
  var
    tmp:longint;
  begin
    inc(deep);
    low[k]:=deep; dfn[k]:=deep; v[k]:=true;
    inc(top);
    stack[top]:=k; f[k]:=true;
    tmp:=head[k];
    while tmp<>-1 do
    begin
      if v[edge[tmp].t]=false then
      begin
        dfs(edge[tmp].t);
        low[k]:=min(low[k],low[edge[tmp].t]);
      end
      else
        if f[edge[tmp].t] then low[k]:=min(low[k],dfn[edge[tmp].t]);
      tmp:=edge[tmp].next;
    end;
    if dfn[k]=low[k] then begin inc(ans); pop(k); end;
  end;
begin
  readln(n,m);
  for i:=1 to n do head[i]:=-1; fillchar(edge,sizeof(edge),0);//初始化
  for i:=1 to m do
  begin
    readln(x,y);
    edge[i].t:=y;
    edge[i].next:=head[x];
    head[x]:=i;
  end;                                   //链接表存储
  fillchar(v,sizeof(v),false); fillchar(f,sizeof(f),false);
  for i:=1 to n do
    if v[i]=false then dfs(i);
  for i:=1 to n do
  begin
    t:=i; tmp:=head[i];
    while tmp<>-1 do
    begin
      if sd[t]<>sd[edge[tmp].t] then inc(cd[sd[i]]);
      t:=edge[tmp].t; tmp:=edge[tmp].next;
    end;
  end;
  for i:=1 to ans do
    if cd[i]=0 then
      if sum=1 then begin writeln(0); halt; end
      else begin inc(sum); tmp:=i; end;             //统计出度为0的连通块
  sum:=0;
  for i:=1 to n do if sd[i]=tmp then inc(sum);
  writeln(sum);
end.



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值