逻辑的联通性

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(n1)/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.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值