Tarjan学习笔记

news/2024/11/30 8:58:52/文章来源:https://www.cnblogs.com/water-flower/p/18568376

强连通分量,缩点算法:Tarjan

代码及模板
强连通图:有向图,任意两点有路径
强连通分量:有向图,强连通子图数量
前置知识:dfs树(dfs序构成的树)
成分:
1.树边:dfs树上的边
(以下三种边是dfs树上没有但原图上有的边)
2.前向边:dfs树的祖先到儿子的边。
3.返祖边(后向边):儿子到祖先的边
4.横向边:旁系亲戚的边(没有直接的祖父关系,可能是兄弟节点之类的)
性质:返祖边和横向边的dfn(dfs序)u < v (不然被直接更新成树边)且因为是dfs,所以v已经判断完了。
所以可以每次遇到一条dfn[u] < dfn[v] 的边,都可以更新low[u] = min(low[u], low[v])
每次递归搜索的时候,都要更新low[u] = min(low[u], low[v])子节点有可能找到了返祖边,那么父节点的low也是儿子的low
循环结束后,如果low[u] = dfn[u],说明u是环的根,栈后面的元素都属于该强联通图,染色,出栈。

具体的代码实现有点有趣。

#include <stack>int dfn[MAXN], tot = 0;
bool instack[MAXN];
int low[MAXN];
int co[MAXN], col = 0;
std::stack<int> stk;void Tarjan(int u)
{dfn[u] = ++tot;low[u] = dfn[u]; // 一开始low[u]是自己,有后向边再更新stk.push(u);instack[u] = true;for(int e = first[u]; e; e = nxt[e]){int v = go[e];if(!dfn[v]){Tarjan(v);low[u] = min(low[u], low[v]); // 子节点更新了,我也要更新// 若子节点没更新,则min能够保证low[u] == dfn[u]}else if(instack[v]) // v访问过且在栈中,意味着u→v是后向边{low[u] = min(low[u], dfn[v]);}}if(low[u] == dfn[u]) // 是SCC中的第一个被访问的节点{co[u] = ++col;while(stk.top() != u) co[stk.top()] = col, instack[stk.top()] = false, stk.pop();// 染色,弹栈instack[u] = false;stk.pop(); // 最后把u弹出去}
}

缩点

即把同一强连通分量的点变成一个点,新点权为scc里所有点权之和

割点

定义:删了该点图不连通的点叫割点
换句话说:若x是割点,则存在 y∈T(x) 满足y不经过 x 能到达的所有点均属于 T(x)。(注:T(x)表示x的dfs子树)
所有的儿子节点的low小于\(dfn_u\)
使得$ low_v \geq dfn_u $,即不能回到祖先,那么 u 点为割点。

割边(桥)

当枚举到边u-v时,若low_v > low_u时,该边为桥。

边,点双连通分量

定义:
在一张连通的无向图中,对于两个点 u 和 v,如果无论删去哪条边(只能删去一条)都不能使它们不连通,我们就说 u 和 v 边双连通

在一张连通的无向图中,对于两个点 u 和 v,如果无论删去哪个点(只能删去一个,且不能删 u 和 v 自己)都不能使它们不连通,我们就说 u 和 v 点双连通

双连通具有传递性, 而双连通不具有传递性

一个边/点双连通分量 == 边/点双连通子图

边双连通分量求法:
在 DFS 生成树上的一个强连通分量,在原无向图中是边双连通分量。可以发现,求边双连通分量的过程实际上就是求强连通分量的过程。

最后记得判重边****

桥(割边)的求法


如上图所示,黑色与绿色边为树边,红色边为非树边。每一条非树边的两个端点都唯一对应了树上的一条由树边构成的简单路径,我们说这条非树边 覆盖 了这条简单路径上所有的边。

在图中,绿色的树边 至少 被一条非树边覆盖,黑色的树边不被 任何 非树边覆盖。

显然,非树边 和 绿色的树边 一定不是桥,黑色的树边 一定是桥。

首先考虑一个暴力的做法,对于每一条非树边,都逐个地将它覆盖的每一条树边置成绿色,时间复杂度为 O(nm)。

考虑用差分优化。对于每一条非树边,在其树上深度较小的端点处打上 -1 标记,在其树上深度较大的端点处打上 +1 标记,然后 O(n) 求出每个点的子树内部的标记和。

对于一个点 u,其子树内部的标记之和等于覆盖了 u 和 fa_u 之间的树边的非树边数量。若这个值等于 0,则 u 和 fa_u 之间的树边是 桥。

void TJ(int u, int fa){dfn[u] = ++cnt, low[u] = dfn[u]; sta.push(u);for(auto v : edge[u]) if(v != fa)/*防止回环*/{if(!dfn[v]) TJ(v, u);low[u] = min(low[u], low[v]);}if(dfn[u] == low[u]){//??? co[++col].push_back(u);while(sta.top() != u) {int x = sta.top();scc[x] = col;co[col].push_back(x), sta.pop();}scc[u] = col;sta.pop();}
}//我自创的优美边双写法

点双的求法 模板

题解 (个人感觉题解写得就很好)
oi-wiki

可能有且只有割点可能同时存在两个点双图中。

每遇到一个割点(见割点的求解方法),就弹出一些点放到一个点双中。

void TJ(int u, int rt) {dfn[u] = low[u] = ++ tot;if(u == rt && !edge[u].size()) //孤立点的特判 scc[++ col].push_back(u);stk[++ tp] = u;for(auto v : edge[u]) {if(!dfn[v]) {TJ(v, rt);low[u] = min(low[u], low[v]);if(low[v] >= dfn[u]) {//点u一定为割点 scc[++ col].push_back(u);while(stk[tp] != v) {//割点点u不会被弹出  scc[col].push_back(stk[tp]);-- tp;} scc[col].push_back(stk[tp]);-- tp;				//注意到 if(low[v] >= dfn[u])是在TJ(v)后的,所以实际执行时间比较晚 //故弹栈中元素最多只能弹到v,剩下的元素要让之前的某个u(dfn更小的节点)来弹出  }}else low[u] = min(low[u], dfn[v]);//}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/840964.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mysql 数据库并发事物导致ABA问题排查解决

问题描述 一个更新计费参数接口,按钮连点导致数据未更新问题。 背景 接口内容逻辑,在一个事物内,先保存更新计费参数,再根据计费参数,重新计算费用,并刷新计费单,结算单,支付单等单据金额信息。按理来讲,这个接口是具备幂等性的,因为即便多次更新,也只是重新计算一遍…

工程化开发谷歌插件到底有爽

工程化开发谷歌插件到底有爽谷歌插件开发本质上就是写一些 html + js + css谷歌开发心得吧 manifest.json 文件{"manifest_version": 3,"name": "发布助手","version": "3.0","description": "前端资源监测&…

12-渗透测试

1、水平越权&垂直越权漏洞实验水平越权lucy用户登入成功后,将url的username参数由lucy改为kobe,即可查看到kobe的信息,实现水平越权垂直越权使用低权限用户pikachu访问添加用户页面,行使管理员admin用户的添加用户权限用户添加成功,实现垂直越权2、密码修改逻辑漏洞实…

vxe-modal 实现弹窗多窗口

官网:https://vxeui.com<template><div><p><vxe-button content="点击弹出" @click="openEvent"></vxe-button></p></div> </template><script> import { VxeUI } from vxe-pc-ui export default …

redis 流量增加过多问题排查解决

背景 Java项目,使用Redis集群。 现象 Redis集群,单台流量增加过多。 在redis服务器上:iftop -npP排查过程 发现流量上涨是同一台机器IP尾号3。到这台机器上查看。 top 命令查看进程idtop -H -p 1748 查看具体线程信息,可以看到,有三个线程执行100多小时,而且占用较多cpu…

RX23E-B系列微控制器是工业传感器设备的理想选择!R5F523E5B介绍,EFR32BG13P732F512GM48-D蓝牙/TH58NVG2S3HTAI0存储IC

RX23E-B系列微控制器是工业传感器设备的理想选择!R5F523E5B介绍,EFR32BG13P732F512GM48-D蓝牙/TH58NVG2S3HTAI0存储ICRX23E-B 系列微控制器具有内置模拟前端 (AFE),是工业传感器设备的理想选择。 与上一代的 RX23E-A 相比,RX23E-B 的24 位 Delta Sigma 模/数转换器在高速性…

100ASK_IMX6ULL-PRO 数码相框扩展项目:支持打开阅读 TXT 文件

背景说明 本篇内容基于百问网嵌入式Linux项目数码相框与文件浏览器和嵌入式Linux电子书阅读器 需求:在文件浏览器界面中支持双击打开TXT类型文件,进入新界面进行文本阅读和翻页控制。 实现思路说明 浏览器界面中响应双击操作,识别TXT类型文件成功后进入阅读器界面。可参考项…

mysql数据库聚合与拆分

1. 背景在用户使用的时候会有统计数据的情况,在多表联查的时候分类时会有,同一个类型出现多次,然后任务需区是出现一次类型名 2. 聚合查询 GROUP_CONCAT(聚合字段) group_by(聚合字段)SELECT report.serialNumber as 病人编号, GROUP_CONCAT(label.lableName) AS &q…

GIS与数字孪生融合:打造智能3D空域管理平台

在数字化转型的浪潮中,地理信息系统(GIS)技术正以其独特的空间分析能力,为城市规划和管理带来革命性的变化。今天,我们将探讨一个前沿话题:基于GIS技术的数字孪生3D空域规划与飞行信息管理平台。 什么是数字孪生?数字孪生,简而言之,就是物理世界中的实体在数字世界中的…

iOS内购——自动续订型会员

原文链接:https://blog.csdn.net/HMOnlyou/article/details/139446159 一、内购支付流程 用户选择商品,发起购买操作,支付完成(会从AppleID账号关联的支付宝/微信 /银行卡完成扣款); 拿到APP本地生成的票据信息发送到苹果服务器验证有效性。1)APP端可以直接向苹果服务器…

微信小游戏sdk接入支付和登录,解决了wx原生不支持ios支付的痛点

本文介绍了微信小游戏sdk登录支付的接入。支付又分为 android支付和 ios支付。由于微信小游戏内不支持ios支付, 通过引入客服会话的方式实现。 侧重于服务器方向,对于复杂的验证签名、解密算法部分提供了Go版本的代码支持【原创】前情提要 微信小游戏是小程序的一种。 项目接入…

vxe-form table 表单修改数据校验错误提示的样式

官网:https://vxeui.com<template><div><vxe-formv-bind="formOptions"@submit="submitEvent"@reset="resetEvent"></vxe-form></div> </template><script> import { VxeUI } from vxe-pc-uiexport …