自行车比赛+纪中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.