0

0

C++怎么实现Tarjan算法_C++强连通分量求解【图论】

裘德小鎮的故事

裘德小鎮的故事

发布时间:2026-02-26 14:27:12

|

256人浏览过

|

来源于php中文网

原创

tarjan算法需用vector模拟栈、全局时间戳、遍历所有未访问节点;dfn和low首次进入即赋值,回溯用min(low[u], low[v])更新;缩点前必须清空所有状态数组。

c++怎么实现tarjan算法_c++强连通分量求解【图论】

tarjan() 函数怎么写才不会栈溢出或漏节点

直接用递归实现 tarjan() 很容易在稠密图或深链图上爆栈,或者因未正确维护 low[]dfn[] 导致某个强连通分量被拆开。核心是:递归入口必须覆盖所有未访问节点;每个节点的 dfn[u]low[u] 必须在第一次进入时立刻赋值;回溯时用 min(low[u], low[v]) 更新,而非 min(low[u], dfn[v])(后者只适用于判断桥/割点)。

实操建议:

立即学习C++免费学习笔记(深入)”;

  • vector<vector>></vector> 存邻接表,避免 map 或 set 带来常数开销
  • 全局计数器 timestamp 初始化为 0,每次进 dfs 就 dfn[u] = low[u] = ++timestamp
  • 入栈操作放在 dfs 开头,出栈必须严格匹配:仅当 dfn[u] == low[u] 时才循环弹出直到 u
  • 别忘了对每个 i0n-1 调用 dfs(i) —— 图不保证连通

stack 和 vector 哪个更适合存栈

stack<int></int> 语义清晰,但实际调试时没法遍历、打印中间状态;而 vector<int></int> + push_back()/pop_back() 完全等价,还能随时用 back() 查顶、用 size() 看长度、甚至输出整个栈内容排查问题。性能无差异,STL vectorpush_back 在末尾是均摊 O(1)。

实操建议:

立即学习C++免费学习笔记(深入)”;

  • 声明为 vector<int> stk;</int>,不是 stack<int></int>
  • 入栈:stk.push_back(u);
  • 出栈到强连通分量:while (stk.back() != u) { int x = stk.back(); stk.pop_back(); comp[x] = comp_id; } stk.pop_back(); comp[u] = comp_id;
  • 别用 stk.empty() 做循环条件——你得靠 dfn[u] == low[u] 触发出栈逻辑

有向图含重边或自环时 tarjan 会错吗

标准 tarjan 对重边和自环天然鲁棒:自环 u→u 会让 dfn[u] 成立,自然被归入自身所在 SCC;重边只是多一次 <code>v == udfn[v] > 0 的判断,不影响 low 更新逻辑。真正要防的是建图时把反向边误加进去(比如无向图当有向图跑),或者邻接表里混入非法索引。

实操建议:

立即学习C++免费学习笔记(深入)”;

  • 建图后检查:所有 v 是否满足 0
  • 遇到 u == v(自环)无需跳过,正常处理
  • 遇到已访问节点 vv 在栈中,才更新 low[u] = min(low[u], dfn[v]);如果 v 已出栈,跳过
  • in_stk[v] 数组标记,而不是查栈里有没有——vector 栈没法高效查找

LeetCode 1192 那种“关键连接”能直接套 tarjan 吗

不能。那是无向图求桥(bridge),要用类似 tarjan 的思想,但更新规则不同:对无向图,不能用 dfn[v] 更新 low[u](否则会把父边误判为后向边),得记录父节点并跳过。而且不需要栈、不需要 SCC 编号,只关心 low[v] > dfn[u] 是否成立。

实操建议:

立即学习C++免费学习笔记(深入)”;

  • 有向图 SCC → 用带栈 + dfn/low + in_stk 的完整 tarjan
  • 无向图找桥 → 去掉栈相关逻辑,加 parent 参数,更新时写 if (v != parent) low[u] = min(low[u], dfn[v]);
  • 同一个项目里混用两种逻辑?务必分开函数名,比如 find_scc()find_bridges(),别共用一个 tarjan()

最常被忽略的一点:缩点后的新图一定是 DAG,但如果你在原图上反复调用 tarjan() 却没清空 dfn[]low[]stkin_stk[],下一轮结果就全乱了。每次运行前重置这些数组,比 debug 半小时更省时间。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

830

2023.08.22

while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

103

2023.09.25

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

850

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

585

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

294

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

210

2025.08.29

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

425

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

597

2023.08.10

batoto漫画官网入口与网页版访问指南
batoto漫画官网入口与网页版访问指南

本专题系统整理batoto漫画官方网站最新可用入口,涵盖最新官网地址、网页版登录页面及防走失访问方式说明,帮助用户快速找到batoto漫画官方平台,稳定在线阅读各类漫画内容。

331

2026.02.25

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 10.2万人学习

C 教程
C 教程

共75课时 | 5万人学习

C++教程
C++教程

共115课时 | 19.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号