news 2026/4/16 13:49:18

Tarjan全家桶系列--强联通分量

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Tarjan全家桶系列--强联通分量

强联通分量(SCC)

有向图中的一个​​极大子图​,其中任意两个节点uv都​​互相可达​(即存在u→vv→u的路径),则这个子图为一个强联通分量
Tarjan 算法基于深度优先搜索(DFS),利用 DFS 序dfnlow链 来判断一个节点是否是某个强连通分量的“根”(即最早被访问的节点)。

基本定义:

强连通分量(SCC):有向图中,任意两个节点 u, v 互相可达的最大子图。
dfn[u]:节点 u 被 DFS 第一次访问的时间戳(DFS 序)。
low[u]:从 u 出发,通过若干条边(可以走树边、后向边、横叉边),能到达的所有节点中 最小的 dfn 值。
换句话说:low[u] = min{ dfn[v] | v 从 u 出发可达 }

关键性质:

如果在 DFS 回溯时发现low[u] == dfn[u],说明 u 是当前 SCC 的“根”。
因为从 u 出发无法回到比 u 更早访问的节点。
此时,从栈顶到 u 的所有节点构成一个 SCC。

栈的作用:

DFS 过程中,将访问的节点压入栈。
当找到一个 SCC 的根时,从栈中弹出直到 u,这些节点就属于同一个 SCC。

模板

说明:void Run(int _n,const vector<int>adj[])为传入点的数量,vector邻接表数组,运行求出所有强联通分量 。·vector<int> Get()为获取scc数组,即scc[i]i点属于的强连通分量编号

template<intN>structSCC{vector<int>scc;vector<int>stk;intdfn[N],low[N];constvector<int>*adj;intn,clk,tot;//tot:scc数量voiddfs(intu){++clk;dfn[u]=low[u]=clk;stk.push_back(u);for(intto:adj[u]){if(dfn[to]==-1){dfs(to);low[u]=min(low[u],low[to]);}elseif(scc[to]==-1)low[u]=min(low[u],dfn[to]);}if(low[u]==dfn[u]){intv=-1;++tot;do{v=stk.back();stk.pop_back();scc[v]=tot;}while(v!=u);}}voidRun(int_n,constvector<int>adj[]){n=_n;clk=tot=0;stk.clear();fill(low,low+3+n,-1);fill(dfn,dfn+3+n,-1);scc.assign(n+3,-1);this->adj=adj;for(inti=1;i<=n;++i)if(scc[i]==-1)dfs(i);}vector<int>Get(){returnscc;}};

使用示例

template<intN>structSCC{vector<int>scc;vector<int>stk;intdfn[N],low[N];constvector<int>*adj;intn,clk,tot;//tot:scc数量voiddfs(intu){++clk;dfn[u]=low[u]=clk;stk.push_back(u);for(intto:adj[u]){if(dfn[to]==-1){dfs(to);low[u]=min(low[u],low[to]);}elseif(scc[to]==-1)low[u]=min(low[u],dfn[to]);}if(low[u]==dfn[u]){intv=-1;++tot;do{v=stk.back();stk.pop_back();scc[v]=tot;}while(v!=u);}}voidRun(int_n,constvector<int>adj[]){n=_n;clk=tot=0;stk.clear();fill(low,low+1+n,-1);fill(dfn,dfn+1+n,-1);scc.assign(n+3,-1);this->adj=adj;for(inti=1;i<=n;++i)if(scc[i]==-1)dfs(i);}vector<int>Get(){returnscc;}};constintmaxn=2*1e5+20;SCC<maxn>T;vector<int>e[maxn];intmain(){intn,m;//n个点,m条边for(inti=1;i<=m;++i){//输入m条边intu,v;cin>>u>>v;e[u].push_back(v);}T.Run(n,e);//跑tarjanvector<int>scc=T.Get();//获取scc数组,scc[i]=i点属于的强连通分量编号
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/1 7:59:38

手把手教你学Simulink——基于高比例可再生能源渗透的复杂电网建模场景实例:含高比例风电接入的弱电网稳定性分析与仿真

目录 手把手教你学Simulink ——基于高比例可再生能源渗透的复杂电网建模场景实例:含高比例风电接入的弱电网稳定性分析与仿真 一、背景介绍 二、系统结构设计 三、建模过程详解 第一步:创建新 Simulink 项目 第二步:添加主要模块 1. 风电场模型 2. 弱电网模型 3. …

作者头像 李华
网站建设 2026/4/9 18:29:10

学Simulink--基于高比例可再生能源渗透的复杂电网建模场景实例:新能源高渗透下传统同步机主导系统的动态响应建模

目录 手把手教你学Simulink ——基于高比例可再生能源渗透的复杂电网建模场景实例:新能源高渗透下传统同步机主导系统的动态响应建模 一、背景介绍 二、系统结构设计 三、建模过程详解 第一步:创建新 Simulink 项目 第二步:添加主要模块 1. 新能源发电模型 2. 同步…

作者头像 李华
网站建设 2026/4/4 9:13:46

数据结构与算法11种排序算法全面对比分析

一、算法分类概述排序算法是计算机科学中最基础且重要的算法类别&#xff0c;用于将数据元素按照特定顺序重新排列。根据是否通过比较元素大小进行排序&#xff0c;可分为比较排序和非比较排序两大类。以下是11种常见排序算法的全面对比分析。二、基本比较排序算法1. 冒泡排序&…

作者头像 李华
网站建设 2026/4/13 0:23:14

破局 AI 选择焦虑:以生态之力,找准低风险高价值的转型航向

在 AI 技术全面爆发的时代&#xff0c;企业技术决策者正面临前所未有的选择困境&#xff1a;智能客服、智能问数、数字人、代码生成等应用方向层出不穷&#xff0c;每个都看似前景广阔&#xff0c;却受限于有限的资源与未知的风险。选择跟风热门赛道&#xff0c;可能面临投入与…

作者头像 李华
网站建设 2026/4/15 18:34:18

【渗透测试零基础入门】搭建 DVWA 靶场保姆级教程(超详细),收藏这一篇就够了!_dvwa靶场搭建

前言 DVWA代表Damn Vulnerable Web Application&#xff0c;是一个用于学习和练习Web应用程序漏洞的开源漏洞应用程序。它被设计成一个易于安装和配置的漏洞应用程序&#xff0c;旨在帮助安全专业人员和爱好者了解和熟悉不同类型的Web应用程序漏洞。 DVWA提供了一系列的漏洞场…

作者头像 李华
网站建设 2026/4/16 12:15:05

485报文订阅服务

订阅服务结构体 // 用于管理某类服务的数据订阅关系,支持多个订阅者注册/注销,便于模块间解耦和消息分发。 //订阅服务结构体 struct SERVICE_SUB_INFO{ MessageQueue * i_subscribe_list[SUB_MEB_MAX]; //订阅者消息队列指针数组,最多支持8个订阅者(如不同模块/线程对…

作者头像 李华