首页 > 编程语言 >[算法学习笔记] 强连通分量

[算法学习笔记] 强连通分量

时间:2023-07-30 22:44:52浏览次数:38  
标签:连通 dfs 笔记 算法 dfn low 节点 分量

DFS生成树

在介绍强连通分量前,我们先来了解一下DFS生成树。

一棵DFS生成树分为树边,前向边,返祖边(一说反向边),横叉边。我们来画图解释一下:

image

在这棵DFS生成树中,黑色为树边,它是在DFS遍历时获得的,红色为返祖边,顾名思义,从儿子指向父亲或祖先。蓝色为横叉边,它是在搜索的时候遇到子树中的节点的时候形成的。粉色是前向边,它是在搜索的时候遇到子树中的结点的时候形成的。

强连通分量

强连通分量,具有强连通性,极大性。强连通性顾名思义,在一个强连通分量内的节点都是可以直接或间接互相可达的。极大性指一个强连通分量内不能再加入任何一个节点,再加入任何一个节点都不满足强连通性。

强连通分量一般在有向图中讨论,若在无向图中强连通分量就退化成了连通块。

为了更好的理解强连通分量,我们画图举例:

image

在这张图中,有两个强连通分量,分别是\({1,2,3}\)和\({1,5,6}\)。由此我们发现一个点可以同属于两个不同的强连通分量。

Tarjan

求强连通分量的方法有很多,参照OI-wiki,这里主要介绍最常见的Tarjan算法。

在讲解Tarjan 算法求强连通分量前,我们定义:

  • \(dfn_u\) 表示节点\(u\)被dfs遍历时的顺序编号
  • \(low_u\) 表示节点\(u\)经过若干条树边,最多经过一条返祖边能到达的\(dfn\)值最小的点

我们发现,在一个强连通分量中,有且只有一个节点的\(dfn\)值等于\(low\)值,这个节点同时也是一个强连通分量中被最先dfs遍历到的点,也就是\(dfn\)值最小的点。我们不妨将这个节点定义为一个强连通分量中的祖先。在接下来的Tarjan过程中会用到这个重要的性质。

\(low\)值可以在dfs的同时得到,对于一条边\(u-v\),如果:

  • \(v\)还未访问,则\(low\)值还不能确定,所以先dfs \(v\),再用\(low_v\)更新\(low_u\),因为\(u,v\)是一条边,\(v\)能到达的点\(u\)也一定可以。

  • \(v\)已经访问,且\(v\)能到达\(u\),我们发现如果出现这种情况若可以更新\(low_u\)则\(u-v\)是返祖边,故用\(dfn_v\)更新\(low_u\)。

  • \(v\)已经访问,但\(v\)不能到达\(u\),不做处理。

那么我们如何确定\(v\)能否到达\(u\)呢?

容易发现需要判定\(v\)能否到达\(u\)的时候属于上文第二种情况,即出现返祖边。我们可以在dfs的时候维护一个栈,每次dfs将当前节点压入栈,这样判定\(v\)能否到达\(u\)的时候我们只需要判定\(u\)是否在栈中就可以了。

我们现在求出了每个节点的\(low\)值,如何求强连通分量呢?

这里就用到了前面所提到的性质,在一个强连通分量中,有且仅有一个节点的\(dfn\)值等于\(low\)值,这个节点也是一个强连通分量中\(dfn\)值最小的点,我们称之为一个强连通分量的祖先。因此,在回溯的时候只需要判断该节点的\(dfn\)值是否等于\(low\)值,如果相等则证明该节点是一个强连通分量的祖先,那么在栈中祖先节点以上的点都属于该强连通分量,循环出栈,统计答案+1即可。


强连通分量一般和缩点连用,由于强连通分量的极大性,若对强连通分量进行缩点,显然变成了有向无环图。(若有环则不满足极大性,也就是说两个强连通分量还能合并成一个新的强连通分量,显然不可)。

缩完点后的强连通分量由于变成了DAG,所以可以dp,可以最短路。

标签:连通,dfs,笔记,算法,dfn,low,节点,分量
From: https://www.cnblogs.com/SXqwq/p/17575709.html

相关文章

  • C#冒泡排序算法
    冒泡排序实现原理冒泡排序是一种简单的排序算法,其原理如下:从待排序的数组的第一个元素开始,依次比较相邻的两个元素。如果前面的元素大于后面的元素(升序排序),则交换这两个元素的位置,使较大的元素“冒泡”到右侧。继续比较下一对相邻元素,重复步骤2,直到遍历到数组的倒数第二......
  • croe5.0学习笔记(5)建模技巧
    1.建模技巧1.1指定曲面偏移1.2  ......
  • mermaid学习笔记
    mermaid功能(基础)关于设计各种图来梳理工程接口流程图定义graph[TB|BT|LR|RL]说明是流程图(参数代表从上往下还是从左往右)其他概念---:实线|-->:带箭头实线|==>:带箭头粗实线并且在也可以(==|--)text(--|==)(-|>)来实现线上有文本的格式定义对象:对象[xxx]代表......
  • C++ Primer 学习笔记——第八章
    第八章IO库前言C++语言并不会直接处理输入输出,而是通过一族定义在标准库中的类型来处理IO。这些类型支持从设备中读取数据、向设备写入数据IO操作。设备可以是文件、控制台窗口等,还有一些类型允许内存IO。IO库定义了读写内置类型值的操作。8.1IO类在之前我们使用的IO类型......
  • python数据分析师入门-学习笔记(爬虫-序言)
    爬虫到底是什么概括爬虫是批量化自动获取既有数据批量化自动既有数据通常获取既有数据特殊批量注册一批账号批量去领取优惠券批量自动下单购物自动做任务(签到)实际应用企业中:竞品调研数据采集办公自动化个人:比如看小说有的网站收费有的网站不收费......
  • 代码随想录算法训练营第四天| LeetCode 24. 两两交换链表中的节点 19.删除链表的倒
    24.两两交换链表中的节点     卡哥建议:用虚拟头结点,这样会方便很多。 本题链表操作就比较复杂了,建议大家先看视频,视频里我讲解了注意事项,为什么需要temp保存临时节点。   题目链接/文章讲解/视频讲解:https://programmercarl.com/0024.%E4%B8%A4%E4%B8%A4%E4%BA%......
  • C++ Primer Plus 第6版 读书笔记(8)第 8章 函数探幽
    第8章函数探幽本章内容包括:内联函数。引用变量。如何按引用传递函数参数。默认参数。函数重载。函数模板。函数模板具体化。通过第7章,您了解到很多有关C++函数的知识,但需要学习的知识还很多。C++还提供许多新的函数特性,使之有别于C语言。新特性包括内联函数、......
  • 关于菜鸡学习RHEL8的一些小笔记--->磁盘分区
    磁盘分区磁盘分区表:MBR表(系统盘使用较多):单块硬盘或者是单个阵列的最大支持2T,并且只能支持四个分区#因为MBR分区类型较多,实际是可以做到分四个以上的分区分区类型:主分区,扩展分区,逻辑分区(逻辑驱动器)GPT表(业务盘使用较多):单块磁盘或者阵列的最大支持是8Z,并且支持128个分区数量(实际上G......
  • 【笔记】DP 优化(WIP)
    7.30DP凸相关决策单调性、斜率优化、凸、四边形不等式,都是凸相关。前置知识四边形不等式:交叉小于包含。\(l_1<l_2<r_1<r_2\tow(l_1,r_1)+w(l_2,r_2)\leqw(l_1,r_2)+w(l_2,r_1)\)。区间包含单调性:包含区间值单调。\(l_1<l_2<r_2<l_1\tow(l_1,r_1)\geqw(l_2,r_2)\)。满足......
  • java基础中(笔记)
    流程控制流程控制语句的分类:1、顺序结构:从上往下,从前往后;2、分支结构(if,switch);3、循环结构(for,while,do...while); if语句if格式:if(关系表达式){语句体;}if(关系表达式){语句体1;}else{语句体2;}if(关系表达式){语句体1;}elseif{语句体2;}elseif{语句体3;}elseif{语......