Description
假如有命题p 一定能推出命题q,则称p 是q 的充分条件,q 是p 的必要条件。
特别的,当p 既是q 的充分条件,又是q 的必要条件时,称p 和q 互为充要条件
现在有n 个命题,其中一些是另一些的充分条件。请问有多少对命题互为充要条件?
Input
第一行三个正整数n,m,分别表示命题数、已知关系数
接下来m 行,每行两个正整数p 和q,表示命题p 是命题q 的充分条件
Sample Input
5 5
1 3
3 2
2 1
4 5
5 4
Output
仅一行,一个整数,表示充要条件的对数
Sample Output
4
样例说明:
4 对充要条件分别是(1, 2)、(2, 3)、(1, 3)、(4, 5)
Data Constraint
对于10% 的数据,n <= 10;m <= 50
对于40% 的数据,n <= 500;m <= 1000
对于另外10% 的数据,数据中保证没有重边且m = n^2
对于100% 的数据,n<= 50000;m <= 600000
题解
其实这个题就是让我们找图中的环,我们可以用tarjan的算法,找到每个拥有的节点个数n,加上
n(n−1)/2
那么讲一下tarjan算法:
Tarjan算法基于定理:在任何深度优先搜索中,同一强连通分量内的所有顶点均在同一棵深度优先搜索树中。也就是说,强连通分量一定是有向图的某个深搜树子树。
这样,我们用low值记录该点所在强连通子图对应的搜索子树的根节点的Dfn值。注意,该子树中的元素在栈中一定是相邻的,且根节点在栈中一定位于所有子树元素的最下方。
强连通分量是由若干个环组成的。所以,当有环形成时(也就是搜索的下一个点已在栈中),我们将这一条路径的low值统一,即这条路径上的点属于同一个强连通分量。
如果遍历完整个搜索树后某个点的dfn值等于low值,则它是该搜索子树的根。这时,它以上(包括它自己)一直到栈顶的所有元素组成一个强连通分量。
标程:
var
i,j,n,m,tot,l,bz1,p,num:longint;
ans:int64;
tov,next,last:array[0..600000]of longint;//形成边的链接数组,详见(SPFA)
bz,zb:array[0..50000]of boolean;//bz为是否访问,zb为是否在栈中
f,x,y,low,dfn:array[0..50000]of longint;//dfn为时间戳,low为祖先,f为栈
function min(a,b:longint):longint;
begin
if a>b then exit(b);
exit(a);
end;
procedure tarjan(x:longint);//tarjan
var
y,i,xx,v:longint;
begin
inc(num);
dfn[x]:=num;
low[x]:=num;
bz[x]:=true;
inc(p);
f[p]:=x;
i:=last[x];
zb[x]:=true;
while i<>0 do
begin
y:=tov[i];
if bz[y]=false then//未被访问
begin
tarjan(y);
low[x]:=min(low[x],low[y]);
end
else
if zb[y] then
low[x]:=min(low[x],dfn[y]);
i:=next[i];
end;
if low[x]=dfn[x] then//已经找到一个强连通分量,弹栈。
begin
xx:=0;
repeat
v:=f[p];
zb[v]:=false;
dec(p);
inc(xx);
until x=v;
ans:=ans+xx*(xx-1) shr 1;
end;
end;
procedure insert(x,y:longint);
begin
inc(tot);
tov[tot]:=y;
next[tot]:=last[x];
last[x]:=tot;
end;
begin
readln(n,m);
for i:=1 to m do
begin
readln(x[i],y[i]);
insert(x[i],y[i]);//形成连通图
end;
tarjan(1);
for i:=1 to n do
if bz[i]=false then
tarjan(i);
writeln(ans);
end.