首页 > 其他分享 >Tarjan 求强连通子图

Tarjan 求强连通子图

时间:2024-06-22 16:58:09浏览次数:19  
标签:Tarjan xfa 子图 连通 子树中 dfn low 求强

重温Tarjan, 网上看了许多博客感觉都讲的不清楚. 故传上来自己的笔记, 希望帮到大家.

提到的一些概念可以参考 oi wiki, 代码也是 oi wiki 的, 因为我不认为我能写出比大佬更好的代码了.


强连通分量: 有向图的最大强连通子图 ( 有向图中任意两点可达 )

  • Tarjan

    1. 对每个结点维护:

      • dfn[x]: 当前节点的 dfs 序.

      • low[x]: x 向下搜索能到达的最小 dfs 序.

    2. 更新 low:

      1. v 未被访问过: 初始 low[v] = dfn[v].v 入栈. 回溯时用 low[v] 更新它的 fa 的 low[ ].

      2. v 被访问过, 且还在栈中: 用 dfs[v] 更新 fa 的 low.

      3. v 被访问过, 不在栈中: 说明这是一个 fa 到 v 的单向访问, 跳过.

    3. 获取答案:

      能让 dfn[x] > low[x], 只有当 X 的子树中某个节点 C 有 { 1. 一条横向边连接到一棵已遍历过的子树  A 2. 一条返祖边连接到  X  的祖先  x f a \begin {cases}1.一条横向边连接到一棵已遍历过的子树~A\\2.一条返祖边连接到~X~的祖先~xfa \end{cases} {1.一条横向边连接到一棵已遍历过的子树 A2.一条返祖边连接到 X 的祖先 xfa​ .

      1. 横向边: 说明 A 没有连接到 C 的边, 否则在之前 C 就被遍历了, 轮不到 X 来遍历. 就用是否 C 在栈中来排除这个情况, 子树 A 中的所有强连通分量之前已经出栈过了( 看代码的实现 ).
      2. 返祖边: 说明 xfa -> x -> c -> xfa 形成环, 在同一个强连通子图( 我们知道, 强连通图是许多环嵌套成的 ). 而且这个子图的根是 xfa 满足 dfn[xfa] = low[xfa].

      此时栈中进来过三类节点 :
      { 1.  在  x  的子树中 { 1.  属于上述  x f a  循环的 ,  在同一个强连通子图 . 2.  不在同一个强连通子图 ,  那递归的讲 ,  在之前就因为属于某个  x f a ′   ( 在  X  的子树中 ) , 而被踢出栈了 . 2. 不在  x  的子树中 ( 即在已遍历过的子树中 ) ,  在栈中的位置一定在  x  的下面 . \begin {cases}1.~在~x~的子树中\begin {cases}1.~属于上述~xfa~循环的,~在同一个强连通子图.\\2.~不在同一个强连通子图,~那递归的讲,~在之前就因为属于某个~xfa'~(在~X~的子树中),而被踢出栈了.\end{cases}\\2. 不在~x~的子树中(即在已遍历过的子树中),~在栈中的位置一定在~x~的下面. \end{cases} ⎩ ⎧​1. 在 x 的子树中{1. 属于上述 xfa 循环的, 在同一个强连通子图.2. 不在同一个强连通子图, 那递归的讲, 在之前就因为属于某个 xfa′ (在 X 的子树中),而被踢出栈了.​2.不在 x 的子树中(即在已遍历过的子树中), 在栈中的位置一定在 x 的下面.​

      故, 回溯时若节点符合 dfn[x] = low[x], 说明当前节点是它所属连通块的最小节点. 栈里它之上所有点都是一个强连通块.

代码:

 const int Maxn = 1e5 + 10;
    
    int dfn[Maxn], low[Maxn], dfncnt, s[Maxn], in_stack[Maxn], tp;
    int scc[Maxn], sc;  // 结点 i 所在 SCC 的编号
    int sz[Maxn];       // 强连通 i 的大小
    
    void tarjan(int u) {
        low[u] = dfn[u] = ++dfncnt, s[++tp] = u, in_stack[u] = 1;
        for (int i = head[u]; i; i = eg[i].nex) {
            const int &v = eg[i].to;
            if (!dfn[v]) {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            } else if (in_stack[v]) {
                low[u] = min(low[u], dfn[v]);
            }
        }
        if (dfn[u] == low[u]) {
            ++sc;
            while (s[tp] != u) {
                scc[s[tp]] = sc;
                sz[sc]++;
                in_stack[s[tp]] = 0;
                --tp;
            }
            scc[s[tp]] = sc;
            sz[sc]++;
            in_stack[s[tp]] = 0;
            --tp;
        }
    }

标签:Tarjan,xfa,子图,连通,子树中,dfn,low,求强
From: https://blog.csdn.net/qq_72715438/article/details/139840282

相关文章

  • Tarjan 求有向图的强连通分量
    重温Tarjan,网上看了许多博客感觉都讲的不清楚.故传上来自己的笔记,希望帮到大家.提到的一些概念可以参考oiwiki,代码也是oiwiki的,因为我不认为我能写出比大佬更好的代码了.强连通分量:有向图的最大强连通子图(有向图中任意两点可达)Tarjan对每个结点维护......
  • Tarjan
    开始我最爱的tarjan吧。说一句,Tarjan最难的不是算法学习,而是如何使用。有向图的强连通分量有向图的强连通分量,是指在有向图的一块地方,在这块地方里面,每个点都能互相到达,这就叫做一个强连通分量定义这里是OIwiki上的定义强连通的定义是:有向图G强连通是指,G中任意两个结......
  • LCA(倍增与Tarjan)
    如果我来到了我们的LCA,我是不是就可以假装偶遇你了首先是倍增法,和ST表如出一辙呢。注意N通常在5e5的范围点击查看代码inthead[N],cnt;structEdge{intfrom,to,nxt;}e[N<<1];voidadd(intu,intv){e[++cnt].from=u;e[cnt].to=v;......
  • Tarjan模板
    Tarjan模板#include<iostream>#include<vector>#include<algorithm>#include<math.h>#include<sstream>#include<string>#include<string.h>#include<iomanip>#include<stdlib.h>#include<map>#include......
  • 图的连通性(tarjan) 学习笔记
    本文可能含有:部分代码省略,部分资源来源于网络,极其模糊不清的语言表述,粗浅到浮于言表的对于此算法的认识。本文仅用于个人学习与报告使用。若有侵权,请洛谷私信联系笔者要求删除。就连上述文字都是抄袭大佬@GClock_519的,可以看得出笔者拙劣的语文水平(图的连通性相关,顾名思义,......
  • tarjan学习笔记
    在Tarjan算法中为每个结点u维护了以下几个变量:dfn[u]:深度优先搜索遍历时结点u被搜索的次序。low[u]:设以u为根的子树为Subtree(u)。 low[u]定义为以下结点的dfn的最小值: Subtree(u)中的结点;从Subtree(u)通过一条不在搜索树上的边能到达的结点。如何计算low?首先让low[x]......
  • tarjan
    一、缩点题目链接https://www.luogu.com.cn/problem/P3387题目大意题目思路缩点+拓扑序+dp代码#include<iostream>#include<queue>#include<cstring>#include<algorithm>#include<set>#definepipair<int,int>constintN=1e4+5,M=1e5......
  • Tarjan 求双连通分量(点双连通分量、边双连通分量)
    注意:本文只针对无向图。对于无向图,显然不能只考虑简单的连通关系,应该研究一些更强的连通关系:双连通。前置芝士点双连通分量:若一个连通分量任意两点间都存在至少两条不经过(除起点和终点外)相同点的路径,我们就称这个连通分量为点双连通分量。边双连通分量:同理,若一个连通分量......
  • tarjan
    桥定义:删除这条边后连通块数量加1思考先暴力搜出一棵树,然后对于每一条非树边都会构成一个环,这个环上的边就不可能是桥了(拿样例来看)\(1\rightarrow2\)和\(5\rightarrow6\)就是桥假如用\(lca\)来维护加一个树上差分码量就有点惊人了考虑优化如果搜树的顺序改为\(df......
  • Tarjan板子
    Tarjan画图必备强连通分量(有向边)常见题建好有向图找强连通分量,同时记录每个强连通分量中节点的个数找节点个数最小的强连通分量点击查看代码structEdge{ intto,next;}edge[N];voidadd(intu,intv){ edge[++cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt;......