Tarjan在图论中的应用(二)——用Tarjan来求割点与割边
前言:\(Tarjan\)
求割点和割边建立在 \(Tarjan\)算法的基础之上,因此建议在看这篇博客之前先去学一学\(Tarjan\)。
回顾\(Tarjan\)中各个数组的定义
首先,我们来回顾一下\(Tarjan\)中各个数组的定义:
\(dfn[\) \(]\):每个点的\(dfs\)序。
\(low[\) \(]\):每个点能到达的\(dfs\)序最小的节点的\(dfs\)序。
而其他数组在求割点和割边的过程中则不太必要了。
割点
首先,我们要了解一下割点的定义:把这个点去掉之后,这个点所在的联通块就会被分成若干个联通块。
既然这样,也就是说,只要这个节点某一个子节点所到达的节点的\(dfs\)序大于等于该节点的\(dfs\)序,即它的这个子节点无法到达\(dfs\)序小于该节点的节点,就说明它是一个割点了。
而对于一个联通块第一个访问的节点,则需特判,如果它在遍历完一个节点所能遍历到的所有节点,还能找到没有被遍历过的节点,就说明它是一个割点。
代码如下:
inline void Tarjan(int x,int lst)//Tarjan求割点
{
register int i,tot=0;//tot记录访问到的子节点个数
for(dfn[x]=low[x]=++d,i=lnk[x];i;i=e[i].nxt)//枚举每一个子节点
{
if(!(e[i].to^lst)) continue;//如果这个节点是当前节点的父亲节点,就跳过
if(!dfn[e[i].to])//如果这个子节点没有被访问过
{
Tarjan(e[i].to,x),low[x]=min(low[x],low[e[i].to]),++tot;//遍历该子节点,更新low[x],并将tot加1
if(lst&&low[e[i].to]>=dfn[x]) IsCut[x]=1;//如果当前节点不是一个联通块第一个访问的节点,且当前节点的这个子节点dfs序大于等于当前节点的dfs序,那么就说明当前节点是割点
}
else low[x]=min(low[x],dfn[e[i].to]);//更新low[x]
}
if(!lst&&tot>=2) IsCut[x]=1;//如果当前节点是联通块第一个节点,且访问到的子节点个数≥2,那么就说明当前节点是割点
}
割边
还是一样,先了解一下割边的定义:把这条边去掉之后,这条边所在的联通块就会被分成若干个联通块,看起来与割点的定义很像。
因此,如果一条边所连接的两个节点,若其中\(dfs\)序较大的节点不经过这条边所能到达的\(dfs\)序最小的节点大于这条边连接的点中\(dfs\)序较小的节点,就说明这条边是一条割边。
不过还要注意判重的情况,要注意如果有两条相同的边,那么这两条边肯定都不是割边。
代码如下:
inline void Tarjan(int x,int lst)//Tarjan求割边
{
register int i,flag=1;//flag记录当前节点是否第一次访问它的父亲节点
for(dfn[x]=low[x]=++d,vis[Stack[++top]=x]=1,i=lnk[x];i;i=e[i].nxt)//枚举每一个子节点
{
if(flag&&!(e[i].to^lst)) {flag=0;continue;}//如果是第一次访问父亲节点,就将flag标记为0,并跳过这条边
if(!dfn[e[i].to])//如果这个子节点没有被访问过
{
Tarjan(e[i].to,x),low[x]=min(low[x],low[e[i].to]);//访问这个节点,并更新low[x]
if(low[e[i].to]>low[x]) IsBridge[i]=1;//如果这条边连向的另一个节点所能到达的dfs序最小的节点大于该节点的dfs序,就说明这条边是割边
}
else if(vis[e[i].to]) low[x]=min(low[x],dfn[e[i].to]);//否则,更新low[x]
}
}
Tarjan在图论中的应用(二)——用Tarjan来求割点与割边的更多相关文章
- Tarjan 强连通分量 及 双联通分量(求割点,割边)
Tarjan 强连通分量 及 双联通分量(求割点,割边) 众所周知,Tarjan的三大算法分别为 (1) 有向图的强联通分量 (2) 无向图的双联通分量(求割点,桥) ...
- tarjan求割点与割边
tarjan求割点与割边 洛谷P3388 [模板]割点(割顶) 割点 解题思路: 求割点和割点数量模版,对于(u,v)如果low[v]>=dfn[u]那么u为割点,特判根结点,若根结点子树有超过 ...
- Tarjan 算法求割点、 割边、 强联通分量
Tarjan算法是一个基于dfs的搜索算法, 可以在O(N+M)的复杂度内求出图的割点.割边和强联通分量等信息. https://www.cnblogs.com/shadowland/p/587225 ...
- Tarjan在图论中的应用(一)——用Tarjan来实现强连通分量缩点
前言 \(Tarjan\)是一个著名的将强连通分量缩点的算法. 大致思路 它的大致思路就是在图上每个联通块中任意选一个点开始进行\(Tarjan\)操作(依据:强连通分量中的点可以两两到达,因此从任意 ...
- Tarjan在图论中的应用(三)——用Tarjan来求解2-SAT
前言 \(2-SAT\)的解法不止一种(例如暴搜?),但最高效的应该还是\(Tarjan\). 说来其实我早就写过用\(Tarjan\)求解\(2-SAT\)的题目了(就是这道题:[2019.8.14 ...
- hihoCoder 1183 连通性一·割边与割点(Tarjan求割点与割边)
#1183 : 连通性一·割边与割点 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 还记得上次小Hi和小Ho学校被黑客攻击的事情么,那一次攻击最后造成了学校网络数据的丢 ...
- 【模拟7.25】回家(tarjan V-DCC点双连通分量的求法及缩点 求割点)模板题
作为一道板子题放在第二题令人身心愉悦,不到一个小时码完连对拍都没打. 关于tarjan割点的注意事项: 1.在该板子中我们求的是V-DCC,而不是缩点,V-DCC最少有两个点组成,表示出掉一个块里的任 ...
- POJ 1144 Network(tarjan 求割点个数)
Network Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 17016 Accepted: 7635 Descript ...
- 利用Tarjan算法解决(LCA)二叉搜索树的最近公共祖先问题——数据结构
相关知识:(来自百度百科) LCA(Least Common Ancestors) 即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先. 例如: 1和7的最近公共祖先为5: 1和5的 ...
随机推荐
- Spark Task 概述
Task的执行流程: 1. Driver端中的 CoarseGrainSchedulerBackend 给 CoarseGrainExecutorBacken 发送 LaunchTask 消息 2. ...
- JVM调试过程
一.查看系统情况 Linux查看CPU和内存使用情况 二.查看JVM启动参数 2.1 jcmd JVM诊断之查看运行参数
- 洛谷P3138 [USACO16FEB]负载平衡Load Balancing_Silver
P3138 [USACO16FEB]负载平衡Load Balancing_Silver 题目描述 Farmer John's NN cows are each standing at distinct ...
- oracle例程
原创转载请注明出处 启动例程: 数据库启动例程的3个步骤 启动例程(NOMOUNT状态):读取参数文件,分配SGA和启动后台进程. 装载数据库(MOUNT状态):根据初始化参数control_file ...
- 洛谷 P1439 【模板】最长公共子序列LCS 解题报告
题目传送门 是一道十分经典的LCS问题 很容易想到 的一般算法:主题代码如下: for (int i = 1; i <= n; i++) for (int j = 1; j <= n; ...
- linux 向文本指定位置写入内容
sed -i "37 r a.txt" test.txt ====== 向test.txt 的第37行后,也就是38行后写入a.txt的内容 sed -i "38i aa ...
- 基于C#编程语言的Mysql常用操作
一.开始需要先将C#中与mysql相关的引用添加进来 using MySql.Data.MySqlClient; 二.创建一个database MySqlConnection m_conn = new ...
- 从左到右的滑块-Au3
说明:使用selenium自动化登陆时会弹出滑块,做人机识别,使用Au3模拟鼠标移动轨迹--可验证通过 #include <MsgBoxConstants.au3> #include &l ...
- IIS断开连接之后internet信息服务里面不显示本地计算机的解决方法
今天我断开了IIS的本地计算机连接之后,出现了无法连接的情况.具体如图: 解决方法: 右击->所有服务->重新启动iis即可.
- 敏捷开发(Agile development)
敏捷开发(Agile development) 敏捷开发是一种以人为核心.迭代.循序渐进的开发方法.在敏捷开发中,软件项目的构建被切分成多个子项目,各个子项目的成果都经过测试,具备集成和可运行的特征. ...