C++的算法:Kosaraju算法与Tarjan算法

【图论】Kosaraju算法详解 讲 Kosaraju 算法之前要先知道什么是强连通分量(SCC) 强连通分量 对于一个有向图顶点的子集 S ,如果在 S 内取两个顶点 u 和 v ,都能找到一条从 u 到 v 的路径,那么就称 S 是强连通的。 如果在强连通的顶点集合 S 中加入其他任意顶点集合后,它都不再是强连通的,那么就称 S 是原图的一个强连通分量(SCC:strongly connected componen... 阅读详情

        在图论中,强连通分量(Strongly Connected Components, SCC)是一个重要的概念。强连通分量是指在一个有向图中,一组顶点的任意两点之间都存在双向可达路径的顶点的集合。在实际应用中,如社交网络分析、网络流量分析等方面,强连通分量的计算具有广泛的应用。C++中,Kosaraju算法和Tarjan算法是两种常用的求解强连通分量的算法。

        Kosaraju算法是一个基于深度优先搜索(DFS)的算法,其基本原理分为两步:

        1. 第一次DFS遍历:从任意节点开始进行深度优先搜索,并对遍历过的节点进行标记。搜索结束后,可以得到一个节点的逆后序序列。
        2. 第二次DFS遍历:根据逆后序序列,从后往前对每个节点进行深度优先搜索,并标记属于同一个强连通分量的节点。

        示例:求出每个节点所属的强连通分量编号,代码如下。

#include <iostream>
#include <vector>
#include <stack>
#include <cstring>
using namespace std;

vector<int> adj[100]; // 邻接表存储图
bool visited[100]; // 标记节点是否被访问过
int scc[100]; // 存储每个节点所属的强连通分量编号
int scc_count; // 强连通分量计数器
stack<int> stk; // 用于存储DFS遍历的节点

// 第一次DFS遍历,得到逆后序序列
void dfs1(int v) {
    visited[v] = true;
    for (int i = 0; i < adj[v].size(); i++) {
        int u = adj[v][i];
        if (!visited[u]) {
            dfs1(u);
        }
    }
    stk.push(v); // 将节点压入栈中,得到逆后序序列
}

// 第二次DFS遍历,标记强连通分量
void dfs2(int v, int id) {
    visited[v] = true;
    scc[v] = id; // 标记节点所属的强连通分量编号
    for (int i = 0; i < adj[v].size(); i++) {
        int u = adj[v][i];
        if (!visited[u]) {
            dfs2(u, id);
        }
    }
}

// Kosaraju算法主函数
void kosaraju() {
    memset(visited, false, sizeof(visited));
    for (int i = 0; i < 100; i++) { // 假设节点编号从0到99
        if (!visited[i]) {
            dfs1(i); // 第一次DFS遍历
        }
    }
    memset(visited, false, sizeof(visited));
    scc_count = 0;
    while (!stk.empty()) {
        int v = stk.top();
        stk.pop();
        if (!visited[v]) {
            dfs2(v, scc_count++); // 第二次DFS遍历,并更新强连通分量计数器
        }
    }
}

int main() {
    // 构建图(以邻接表形式)
    adj[0].push_back(1);
    adj[1].push_back(2);
    adj[2].push_back(0);
    adj[2].push_back(3);
    adj[3].push_back(3);

    kosaraju(); // 调用Kosaraju算法

    // 输出每个节点所属的强连通分量编号
    for (int i = 0; i < 4; i++) {
        cout << "Node " << i << " belongs to SCC " << scc[i] << endl;
    }

    return 0;
}

        Tarjan算法是一种基于深度优先搜索和栈的算法,通过维护一个栈和一个访问时间戳数组来实现强连通分量的求解。其基本步骤如下:

        1. 初始化所有节点的访问状态为未访问,时间戳为0,最低访问时间戳为无穷大。
        2. 对每个未访问的节点进行深度优先搜索,同时更新访问状态和时间戳。
        3. 如果一个节点的后继节点已经在栈中且其最低访问时间戳小于当前节点的访问时间戳,则找到了一个强连通分量。
        4. 通过不断回溯和弹出栈中元素,直到不再满足上述条件为止,从而得到一个强连通分量。
        5. 重复上述步骤,直到所有节点都被访问过。

        示例:求出每个强连通分量,代码如下。

#include <iostream>
#include <vector>
#include <stack>
#include <cstring>
using namespace std;

vector<int> adj[100]; // 邻接表存储图
int index; // 时间戳计数器
int low[100]; // 节点能够回溯到的最早时间戳
bool instack[100]; // 节点是否在栈中
int scc_count; // 强连通分量计数器
stack<int> stk; // 用于DFS遍历的栈
vector<int> scc_list[100]; // 存储每个强连通分量的节点

void tarjan(int v) {
    int i;
    low[v] = index++;
    stk.push(v);
    instack[v] = true;
    for (i = 0; i < adj[v].size(); i++) {
        int u = adj[v][i];
        if (low[u] == -1) { // 如果u未访问过
            tarjan(u);
            if (low[u] < low[v]) {
                low[v] = low[u];
            }
        } else if (instack[u]) { // 如果u在栈中
            if (low[u] < low[v]) {
                low[v] = low[u];
            }
        }
    }
    if (low[v] == index - 1) { // 发现一个强连通分量
        int j;
        do {
            j = stk.top();
            stk.pop();
            instack[j] = false;
            scc_list[scc_count].push_back(j);
        } while (j != v);
        scc_count++;
    }
}

void tarjan_algorithm() {
    memset(low, -1, sizeof(low));
    memset(instack, false, sizeof(instack));
    index = 0;
    scc_count = 0;
    for (int i = 0; i < 100; i++) { // 假设节点编号从0到99
        if (low[i] == -1) {
            tarjan(i); // 对每个未访问的节点进行Tarjan算法
        }
    }
}

int main() {
    // 构建图(以邻接表形式)
    adj[0].push_back(1);
    adj[1].push_back(2);
    adj[2].push_back(0);
    adj[2].push_back(3);
    adj[3].push_back(3);

    tarjan_algorithm(); // 调用Tarjan算法

    // 输出每个强连通分量
    for (int i = 0; i < scc_count; i++) {
        cout << "SCC " << i << ": ";
        for (int j = 0; j < scc_list[i].size(); j++) {
            cout << scc_list[i][j] << " ";
        }
        cout << endl;
    }

    return 0;
}

        Kosaraju算法和Tarjan算法都是用于求解有向图强连通分量的经典算法。Kosaraju算法通过两次深度优先搜索来求解,而Tarjan算法则利用时间戳和栈来实现更高效的求解。在实际应用中,可以根据图的特点和具体需求选择合适的算法。

强连通分量算法详解:Kosaraju与Tarjan的C++实现与实战 在有向图的分析中,强连通分量是理解节点间相互可达关系的核心概念。当图规模较大、结构较复杂时,手工判断回路变得不可行,需要借助基于深度优先搜索的系统化算法来实现高效划分。Kosaraju算法通过两遍DFS和反向图直观地分离分量,而Tarjan算法利用时间戳与回溯值在一遍遍历中完成求解,在空间和效率上更具优势。这一技术不仅是图论进阶的基石,能够支撑依赖关系解析、课程安排冲突检测、数据库死锁识别等真实工程场景,更是进一步进行缩点、构造DAG以及执行拓扑排序等后续操作的前提。掌握强连通分量算法,能够帮助开发者更从容 阅读详情

相关推荐

图论中的强连通分量:Kosaraju算法详解

在图论的世界里,强连通分量(Strongly Connected Components, SCC)就像隐藏在有向图中的“小圈子”——圈子里的每个节点都能互相到达。无论是社交网络中的“死党群”、编译器中的“循环结构”,还是金融网络中的“欺诈闭环”,SCC都是理解复杂系统结构的关键。而Kosaraju算法则是挖掘这些“小圈子”的经典工具,它通过两次DFS遍历和逆图转换,以线性时间复杂度(O(V+E))高效解决SCC问题。

AI天才研究院 709

Kosaraju算法,超全解释

Kosaraju算法是一种用于寻找有向图强连通分量的经典算法。它由印度计算机科学家Sambasiva Kosaraju于1978年提出。在本文中,我将会详细介绍Kosaraju算法的原理、步骤以及实现方式,并对该算法进行性能分析和优化。

m0_72410588的博客 4744

有向图的强连通分量: Kosaraju算法和Tarjan算法详解

本文介绍强连通分量问题的解法, 主要介绍Kosaraju和Tarjan算法.

一些C++相关的技术笔记或者教程. 1909

C语言经典算法之Kosaraju算法

Kosaraju算法是用来寻找有向图的强连通分量的一种线性时间复杂度算法。

weixin_56154577的博客 1911

Kosaraju算法详解

主要为大家详细介绍了Kosaraju算法,Kosaraju算法可以计算出一个有向图的强连通分量,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

K8s入门教程(一)

本教程提供了Kubernetes(K8s)的入门指南,涵盖了从基础概念到实战操作的全面内容。首先介绍了Kubernetes的定义和核心功能,如自动化部署、弹性伸缩、自我修复等。接着,详细讲解了如何在macOS上安装Minikube和kubectl工具,以及如何使用这些工具创建和管理Pod、Deployment和Service等核心资源。教程还包括了实战案例,如部署Nginx应用,并介绍了高级特性如滚动更新和自动伸缩。最后,提供了常见问题的解决方案,帮助用户快速上手和解决实际使用中的问题。

2401_82505179的博客 1690

【DayDayUp】【算法_图_强连通_之一_Kosaraju算法和Tarjan算法】

【坚持不能偷懒】 譬如一个有向图,V个点,E条边 如果一个区域中的每个点都能到达任意另一个点 则称这个区域强连通 【相对朴素的Kosaraju算法】 需要对图Dfs两发 第一遍Dfs在dfs时记录一个时间(下面栗子里,括号里为时间) 譬如A->B->C B->D这样的图 我搜索A(1) ->搜索B(2) ->搜索C(3) 这时候,发现没了,退出 所以C变成(3

under_sky_dxj的博客 621

3DGS 2025实战指南:从安装到训练全流程解析

本文提供了3D Gaussian Splatting (3DGS) 从零开始的完整实战指南。详细解析了使用gsplat库进行环境配置、依赖安装(包括pycolmap和fused-ssim)、数据准备与COLMAP处理、核心训练流程及参数调优,并探讨了2025年3DGS在动态场景、可控编辑等领域的最新进展,帮助开发者快速掌握这一前沿3D重建技术。

b3n4m5q6w7的博客 359

POJ 2553 The Bottom of a Graph 强连通分量+缩点 tarjan or kosaraju

题目的意思是求有向图中满足“自己可达的顶点都能到达自己”的顶点个数 显然,在一个强连通分量中,每个点都符合要求,但是 如果强连通分量中有某个点跟外面的某个点相连了,这个强连通分量就不符合要求了,很显然,外面的点是无法回到这个点上的,如果能回到这个点,就是强连通分量中的一员了,这是矛盾的。 那么结论就是,缩点后,求出度为0的强连通分量中的顶点。 tarjan写的 #include #inc

水 1010

centos7下100T存储扩容(LVM)至150T

查看新增磁盘情况lsblk,fdisk -l [root@localhost ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sr0 11:0 1 4.2G 0 rom vda 252:0 0 80G 0 disk ├─vda1 252:1 0 1G 0 part /boot └─vda2 252:2

tiyager的博客 1025

ArcGIS Pro 3.0 加载天地图WMTS服务,解决偏移问题的保姆级教程(附最新Key申请流程)

本文详细介绍了在ArcGIS Pro 3.0中精准加载天地图WMTS服务的全流程,包括最新Key申请流程、解决地图偏移问题的关键配置步骤以及常见问题排查方法。通过设置`esri`参数和统一坐标参考,确保地理数据与天地图底图精确匹配,提升GIS空间分析的准确性。

weixin_28713947的博客 307

POJ 2762 Going from u to v or from v to u? 图的单连通性 tarjan or kosaraju

虽然本题是求单连通的,但是我们需要先求强连通分量,因为,强连通分量中存在双向路径,因此可以缩点,缩点后就好处理多了。 如果要满足题意,缩点后的树必须是一条链,而且所有边的方向都是一样的,如果出现分支,很容易证明会出现不可到达的一对点。 那么剩下的就是求最长链的顶点数是否等于强连通分量的个数了。 那么就可以使用拓扑排序,或者直接DFS。 拓扑排序中,不能出现同时有两个点的入度为0。 DFS

水 1124

SAP-ABAP:SAP基础数据校验工具开发系列博客(共5篇) 第一篇:需求梳理与架构设计:从零搭建SAP主数据校验能力底座

摘要: 本系列博客介绍SAP主数据校验工具的开发和设计,旨在解决物料、供应商、客户等主数据录入不规范、关联缺失和合规性问题。第一篇聚焦需求梳理与架构设计,提出分层技术架构(展示层、业务逻辑层、数据访问层),支持实时校验和批量校验两种模式,并详细说明规则引擎设计、SAP系统对接方案及权限管控逻辑。后续篇章将深入规则引擎实现、接口对接、结果可视化和性能优化,帮助构建集中式、可配置的主数据校验能力,提升SAP数据质量。

baidu_35680696的博客 331

SSL 2344 洛谷 2835 信息学奥赛一本通 1383 刻录光盘#floyd,tarjan,kosaraju#

洛谷请关掉优化 题目 求有多少个连通块 分析 floyd+并查集 floyd代码 #include &amp;amp;lt;cstdio&amp;amp;gt; #include &amp;amp;lt;cctype&amp;amp;gt; #include &amp;amp;lt;cstring&amp;amp;gt; using namespace std; int n,m

lemondinosaur的博客 1154

YOLOv12涨点改进 | CVPR 2026 |独家创新首发、特征融合改进篇 | 引入Local Attender 局部注意力算子融合模块,高效捕捉小目标和密集目标的局部上下文特征,助力高效涨点

🚀本文提出LocalAttender模块改进YOLOv12模型,通过局部注意力机制解决传统上采样方法的语义漂移问题。该模块采用固定偏移邻域加权聚合方式,在保持线性计算复杂度的同时有效捕捉小目标和密集目标的局部特征。实验表明,LocalAttender能显著提升检测精度而不增加过多计算负担,且与YOLOv12兼容性强。文章详细介绍了模块原理、实现方法和配置步骤,并提供了两种改进方案的具体yaml配置文件。这一创新为提升目标检测性能提供了高效解决方案。

Ai缝合怪、助力小伙伴高效发论文 120

一文读懂5G网络整体架构(接入网+承载网+核心网)

接入网重构分级(分工更细、效率更高)、承载网三段化升级(管道更宽、更智能)、核心网服务化云化(管理更灵活、成本更低)最终实现“成本最优、资源灵活、场景适配”,才能支撑自动驾驶、工业互联网、智慧城市、VR/AR等各种新场景,真正走进我们的生活。

鲸落寰宇 430

ACM图论__有向图的强连通分支算法

求有向图的强连通分支,主要有两种算法tarjan算法和kosaraju算法,这里介绍tarjan算法先来看几个定义:(1)连通:两个点可以相互到达(2)强连通(strongly connected): 在一个有向图G里,设两个点 a b 发现,由a有一条路可以走到b,由b又有一条路可以走到a,我们就叫这两个顶点(a,b)强连通。(3)强连通分量strongly connected componen...

untilyouydc 3594

【100%通过率】华为OD机试真题 JS 实现【水库蓄水问题】【2023 Q1 | 100分】

给定一个长度为 n 的整数数组height。数组的元素表示山的高度,选择两个元素作为水库的边界,求蓄水量的最大值并输出蓄水量最大时的边界下标(蓄水量相同时输出下标较近的)。

MISAYAONE的博客 8173

150904 高速公路 ccf

参考 Kosaraju https://www.cnblogs.com/nullzx/p/6437926.html tarjan https://blog.youkuaiyun.com/qq_34374664/article/details/77488976 思路 求回路也就是求图的强连通分量 共有两种算法:Kosaraju与tarjan,其中Kosaraju算法较易理解但需要两次d...

weixin_30679823的博客 133

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

有向图的强连通分量,割点与桥

有向图的强连通分量 1、Tarjan /* Tarjan算法 复杂度O(N+M) */ #include<iostream> #include<stdio.h> #include<string.h> using namespace std; const int MAXN=20010;//点数 const int MAXM=500...

weixin_30920597的博客 173

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

有向图强连通分量

有向图强连通分量        详情请见刘汝佳>P319        有向图的强连通分量有两个算法,第一个是Kosaraju算法,该算法可以以有向图的每个强连通分量的拓扑顺序给每个强连通分量标记序号.具体代码如下: (G存原图,G2存逆图)        第二个求有向图强连通分量的算法是Tarjan算法.它的时间复杂度也是线性的,不需要计算图的逆且算法常数更小.具体代码如下: #

code 2583

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

图搜索算法终极指南:BFS、DFS与强连通分量完整解析

图搜索算法是计算机科学中处理图数据结构的基础技术,广泛应用于路径规划、网络分析、社交网络挖掘等领域。在GitHub加速计划的algo/algorithms项目中,提供了完整的C++实现,包括广度优先搜索(BFS)、深度优先搜索(DFS)和强连通分量(SCC)等核心算法,为开发者提供了高效可靠的图算法解决方案。 ## 🔍 什么是图搜索算法? 图搜索算法是用于遍历或搜索图数据结构中节点的方法。图

gitblog_00281的博客 939

POJ 2186 强连通分量

比较简单吧。。套模板。。 Gabow #include "cstdlib" #include "cctype" #include "cstring" #include "cstdio" #include "cmath" #include "algorithm" #include "vector" #include "string" #include "iostream" #i

O(1) 的小乐 1003

poj2553 - The Bottom of a Graph

想看更多的解题报告:http://blog.youkuaiyun.com/wangjian8006/article/details/7870410                                   转载请注明出处:http://blog.youkuaiyun.com/wangjian8006 题目大意:如果v点能够到的点,反过来能够到达v点,则称这个点为sink点,输出所有的sink点 解题思路:

贰圣 2127

代码随想录 打卡第五十三天

【代码】代码随想录 打卡第五十三天。

weixin_47721341的博客 24
上一篇: C++的近邻算法详解及应用
下一篇: C++的算法:割点与割边
全栈工程师Linda
博客等级 码龄20年 1348粉丝 129原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈工程师Linda

感恩您的鼓励,我会继续创作作品

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值