tarjan(强连通分量) python (P2863 The Cow Prom S)

tarjan算法

时间戳dfn[x]:节点x第一次被访问的顺序

追溯值low[x]:从节点x出发,能访问到的最早时间戳

三步 入,回,离

1入:入x时,盖戳dfn[x]=lowx[x]=tot,tot:被访问的顺序

2枚举:枚举x的邻接的节点y

  1. 邻接点未访问时,对y深搜,回x节点时,用low[y]更新low[x]

子节点y能访问到的节点,x一定的能访问到,x时y的父节点

  1. 若y已访问且在栈中,说明y是祖先节点或左子树节点
  2. y已经不在栈中,不做处理

3离开x时,判断是否是强连通分量的根节点,即dfn[x]==low[x]

记录强连通分量,遍历完一个强连通分量才可出栈

洛谷:P2863 [USACO06JAN]The Cow Prom S

https://www.luogu.com.cn/problem/P2863

import sys
sys.setrecursionlimit(100000000)
n,m=map(int,input().split())
e=[[] for i in range(n+1)]
for i in range(m):
    a,b=map(int,input().split())
    e[a].append(b)


dfn=[0]*(n+1)
low=[0]*(n+1)
stk=[0]*(n+1)
instk=[0]*(n+1)
scc=[0]*(n+1)
siz=[0]*(n+1)
tot=cnt=top=0
vis=[0]*(n+1)
def tarjan(x):
    global tot,cnt,top
    tot=tot+1
    top=top+1
    vis[x]=1
    dfn[x]=low[x]=tot#入x,盖戳,入栈
    stk[top]=x
    instk[x]=1
    for l in e[x]:
        if not dfn[l]:
            tarjan(l)
            low[x]=min(low[x],low[l])#回
        elif instk[l]:
            low[x]=min(low[x],low[l])
    if dfn[x]==low[x]:#离,x是scc的根
        cnt=cnt+1
        while True:
            y=stk[top]#弹栈
            top=top-1
            instk[y]=0#不在栈中,标记为0
            scc[y]=cnt#scc的编号,属于第几个联通图
            siz[cnt]=siz[cnt]+1#scc的大小
            if y==x:
                break

for i in range(1,n+1):
    if vis[i]==0:
        tarjan(i)
ans=0
for i in range(1,n+1):
    if siz[i]>=2:
        ans=ans+1
print(ans)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值