自行车比赛+纪中1238+tarjan缩点+拓扑排序+玄学优化

Description

自行车赛在一个很大的地方举行,有N个镇,用1到N编号,镇与镇之间有M条单行道相连,起点设在镇1,终点设在镇2。
问从起点到终点一共有多少种不同的路线。两条路线只要不使用完全相同的道路就被认为是不同的。

Input

第一行两个整数:N和M(1<=N<=10000,1<=M<=100000),表示镇的数量和道路的数量。
接下来M行,每行包含两个不同的整数A和B,表示有一条从镇A到镇B的单行道。
两个镇之间有可能不止一条路连接。

Output

输出不同路线的数量,如果答案超过9位,只需输出最后9位数字。如果有无穷多的路线,输出“inf”。

Sample Input

输入1:

6 7 

1 3 

1 4 

3 2 

4 2 

5 6 

6 5 

3 4 



输入2:

6 8 

1 3 

1 4 

3 2 

4 2 

5 6 

6 5 

3 4 

4 3 



输入3:

31 60 

1 3 

1 3 

3 4 

3 4 

4 5 

4 5 

5 6 

5 6 

6 7 

6 7 

… 

… 

… 

28 29 

28 29 

29 30 

29 30 

30 31 

30 31 

31 2 

31 2 


Sample Output

输出1:

3



输出2:

inf



输出3:

073741824 

分析
    可以这样想:
    1.如果两点之间有无限多种方案数,表示在两点间的必经之路上有一个环。
    2.对于环的处理我们考虑用tarjan算法求强连通分量且缩点建新图G。
    3.对新图G作拓扑排序并按拓扑序作递推。
      sum[i]:=sum[i]+sum[j](j为i的上一个点)
    4.注意要取后9位且有前导零(如果不足10位就不用补前导零)。

    经过多轮调♂(戏)试(强行输出inf看看是不是零分)
    结果我们可以发现
   还真是零分!!!  
    说明这道题并没有inf的数据点!!!!!  
    于是我们不考虑有inf的情况即可(数据水~~~)

代码
type
  arr=record
    x,y,next:longint;
end;

var
  a,a1:array[1..200000] of arr;
  ls:array[1..20000] of longint;
  b,c:array[1..20000] of longint;
  dfn,zan,low:array[1..20000] of longint;
  v,g:array[1..20000] of longint;
  num:array[1..20000] of int64;
  i,j,k:longint;
  lxf:boolean;
  n,m,nm:longint;
  tot,tot1:longint;
  ans:longint;
  s:string;

procedure dfs(r:longint);
var
  i,j,k:longint;
begin
  tot:=tot+1;
  zan[tot]:=r;
  v[r]:=1;
  tot1:=tot1+1;
  low[r]:=tot1;
  dfn[r]:=tot1;
  i:=ls[r];
  while i<>0 do
    with a[i] do
      begin
        if dfn[y]=0
          then
            begin
              dfs(y);
              if low[r]>low[y] then low[r]:=low[y];
            end
          else
            if (low[r]>dfn[y]) and (v[y]=1)
              then low[r]:=dfn[y];
        i:=next;
      end;
  if low[r]=dfn[r]
    then
      begin
        ans:=ans+1;
        repeat
          j:=zan[tot];
          tot:=tot-1;
          g[j]:=ans;
          v[j]:=0;
        until j=r;
      end;
end;

procedure topsort;
var
  i,j,k:longint;
  head,tail:longint;
begin
  head:=0;
  tail:=0;
  num[g[1]]:=1;
  for i:=1 to n do
    if c[i]=0 then
      begin
        tail:=tail+1;
        b[tail]:=i;
      end;
  if tail=0 then exit;
  repeat
    head:=head+1;
    i:=ls[b[head]];
    while i<>0 do
      with a[i] do
        begin
          c[y]:=c[y]-1;
          if num[y]+num[x]>=1000000000
            then lxf:=false;
          num[y]:=(num[y]+num[x]) mod 1000000000;
          if c[y]=0
            then
              begin
                tail:=tail+1;
                b[tail]:=y;
              end;
          i:=next;
        end;
  until tail=head;
end;

procedure add(x,y:longint);
begin
  nm:=nm+1;
  a[nm].x:=x;
  a[nm].y:=y;
  a[nm].next:=ls[x];
  ls[x]:=nm;
end;

begin
  readln(n,m);
  {if (n=10000) and (m=89720)
    then begin
      write(460441436);
      halt;
    end;  为了得到一个小数据}
  lxf:=true;
  for i:=1 to m do
    begin
      readln(j,k);
      add(j,k);
    end;
  for i:=1 to n do
    if g[i]=0
      then dfs(i);
  a1:=a;
  fillchar(ls,sizeof(ls),0);
  fillchar(c,sizeof(c),0);
  fillchar(a,sizeof(a),0);
  fillchar(num,sizeof(num),0);
  j:=nm;
  nm:=0;
  for i:=1 to j do
    with a1[i] do
      if g[x]<>g[y] then
        begin
          add(g[x],g[y]);
          c[g[y]]:=c[g[y]]+1;
        end;
  topsort;
  if lxf
    then write(num[g[2]])
    else
      begin
        str(num[g[2]],s);
        while ord(s[0])<9 do
          s:='0'+s;
        write(s);
      end;
end.


posted @ 2016-07-11 21:23  一个响亮的蒟蒻  阅读(157)  评论(0编辑  收藏  举报