图论:tarjan 算法求解强连通分量
题目描述
有一个 n n n 个点, m m m 条边的有向图,请求出这个图点数大于 1 1 1 的强连通分量个数。
输入格式
第一行为两个整数 n n n 和 m m m。
第二行至 m + 1 m+1 m+1 行,每一行有两个整数 a a a 和 b b b,表示有一条从 a a a 到 b b b 的有向边。
输出格式
仅一行,表示点数大于 1 1 1 的强连通分量个数。
5 4
2 4
3 5
1 2
4 1
1
提示
数据规模与约定
对于全部的测试点,保证 2 ≤ n ≤ 1 0 4 2\le n \le 10^4 2≤n≤104, 2 ≤ m ≤ 5 × 1 0 4 2\le m\le 5\times 10^4 2≤m≤5×104, 1 ≤ a , b ≤ n 1 \leq a, b \leq n 1≤a,b≤n。
基本概念梳理
强连通图
在一个有向图中,任意两个节点之间都能相互到达,那么这个图就是一个强连通图。
强连通分量(Strongly Connected Components, SCC)
强连通图是非常少的,但是在有向图中,如果存在某些节点子集 A A A,任意两个节点可以相互到达,且如果往子集 A A A 中再加入新的节点,那么子集中任意两个节点之间无法相互到达,那么称这些节点为强连通分量。如下图,共有三个强连通分量,红框中的节点 1 , 2 , 3 1,2,3 1,2,3 组成了一个强连通分量,绿框中的节点 4 , 5 4,5 4,5 组成了另一个强连通分量,蓝框中的节点 6 6 6 是一个强连通分量。

D F S DFS DFS 遍历
之前我们学习 D F S DFS DFS 遍历的时候,有两种常用的遍历方式。
方式 1 1 1:先访问当前节点,再递归相邻节点。(类似求树的深度)
方式 2 2 2:先递归相邻节点,再访问当前节点。(类似求子树大小)
t a r j a n tarjan tarjan 算法思路
对于 t a r j a n tarjan tarjan 算法,我们用的 d f s dfs dfs 遍历 是上面 方式 2 2 2。
对于每个节点来说,有两个重要属性,我通常定义为 i d id id 和 t x tx tx,其中 i d id id 表示 首次到达节点的时间戳, t x tx tx 表示从当前节点出发,可以遍历到的 i d id id 最小的节点的值,对于上面的图,我们可以从节点 1 1 1 出发进行一次【方式 2 2 2】 的 d f s dfs dfs 遍历,试试 可以得到每个节点的 i d id id 值和 t x tx tx 值分别是多少?如下:
节点 1 : i d = 1 , t x = 1 1: id = 1, tx = 1 1:id=1,tx=1。
节点 2 : i d = 2 , t x = 1 2:id = 2, tx = 1 2:id=2,tx=1。
节点 3 : i d = 3 , t x = 1 3:id = 3, tx = 1 3:id=3,tx=1。
节点 4 : i d = 4 , t x = 4 4: id = 4, tx = 4 4:id=4,tx=4。
节点 5 : i d = 5 , t x = 4 5: id = 5, tx = 4 5:id=5,tx=4。
节点 6 : i d = 6 , t x = 6 6: id = 6, tx = 6 6:id=6,tx=6。
通过观察可以发现,同一个强连通分量中的节点,它们的 t x tx tx 值是相等的,而且,强连通分量中的起点的 i d id id 一定等于 t x tx tx。
在整个 d f s dfs dfs 搜索过程中,我们需要借助 栈 来保存遍历到的元素,到达某个节点后,先从这个节点开始搜,搜索结束后,更新当前节点的 t x tx tx 值,所有邻接点全部搜索完后,判断当前节点是否是当前这个强连通分量的起点(即 i d id id 是否等于 t x tx tx),如果是,从栈空间中取出当前强连通分量的所有节点即可。
比如,找第一个强连通分量,栈结构如下:

此时,对于节点 1 1 1 来说,在栈中的位置到栈顶,所有元素都是以 节点 1 1 1 为起点的强连通分量中的元素。
其他两个强连通分量类似,在此不画,可以通过代码来理解。
代码
#include "bits/stdc++.h"
using namespace std;
const int N = 2e4+7, M = 5e4+7;
struct Edge{int v, ne;
}es[M];
struct Node{int id, tx;
}f[N];
int n, t=1, m, u, v, idx = 1, h[N], ans;
stack<int> stk;
bool vis[N]; // 记录节点是否在栈中,在栈中标记为true,否则为false
// dfs函数,传入节点编号,开始从当前节点进行 先搜索后访问的 dfs
void dfs(int u) {f[u].id = t; // 首次到达的时间戳f[u].tx = t++; // 可以回溯到最小的时间戳,初始的时候就是 t,跟id 一样stk.push(u); // 当前节点进栈vis[u] = true; // 所有进栈的元素全部标记for(int e = h[u]; e; e = es[e].ne) { // 链式前向星遍历节点 u 的所有邻接点int v = es[e].v; // u 的 邻接点 vif(f[v].id == 0) { // 节点v 还没有访问过dfs(v); // 先搜索f[u].tx = min(f[u].tx, f[v].tx); // 再更新可以回溯到的最小时间戳} else if(vis[v]) { // 节点v访问过,如果在栈中,那就一定是当前强连通分量中的节点f[u].tx = min(f[u].tx, f[v].tx); // 更新最小时间戳}}if(f[u].id == f[u].tx) { // 节点u 是当前强连通分量中的起点,也可以成为当前强连通分量的根节点int cnt = 0; // 本次强连通分量的节点个数,计算的是大于1 的强连通分量的个数while(!stk.empty() && stk.top() != u) { // 栈顶这些元素都是和 u 一个强连通分量的,而且 u 是这个强连通分量的鼻祖vis[stk.top()] = false; // 出栈更新visstk.pop(); // 出栈cnt++; // 强连通分量中节点数+1}vis[stk.top()] = false; // 本次是 u 节点stk.pop(); // u 出栈cnt++; // 个数+1if(cnt > 1) ans++; // 统计点数大于 1 的强连通分量的个数}
}
// 链式前向星建图
void add(int u, int v) {es[idx] = {v, h[u]};h[u] = idx++;return;
}
int main() {cin >> n >> m;while(m--) {cin >> u >> v;add(u, v); // 有向图}for(int u=1; u<=n; u++) {if(f[u].id == 0) dfs(u); // 当前节点还没有遍历过,开始从当前节点搜}cout << ans << endl;return 0;
}
相关文章:
图论:tarjan 算法求解强连通分量
题目描述 有一个 n n n 个点, m m m 条边的有向图,请求出这个图点数大于 1 1 1 的强连通分量个数。 输入格式 第一行为两个整数 n n n 和 m m m。 第二行至 m 1 m1 m1 行,每一行有两个整数 a a a 和 b b b,表示有一条…...
Haskell语言的物联网
Haskell语言在物联网中的应用 引言 物联网(IoT,Internet of Things)是现代科技发展的重要领域,它将日常生活中的各种设备通过互联网连接起来,实现智能化的控制与管理。随着设备数量的激增,以及数据处理需…...
Java:单例模式(Singleton Pattern)及实现方式
一、单例模式的概念 单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点来访问该实例,是 Java 中最简单的设计模式之一。该模式常用于需要全局唯一实例的场景,例如日志记录器、配置管理、线程池、数据库…...
Python爬虫实战:股票分时数据抓取与存储 (1)
在金融数据分析中,股票分时数据是投资者和分析师的重要资源。它能够帮助我们了解股票在交易日内的价格波动情况,从而为交易决策提供依据。然而,获取这些数据往往需要借助专业的金融数据平台,其成本较高。幸运的是,通过…...
将图片base64编码后,数据转成图片
将图片数据进行base64编码后,可以在浏览器上查看图片,只需在前端加上data:image/png;base64,即可 在线工具: Base64转图片 - 加菲工具...
天翼云910B部署DeepSeek蒸馏70B LLaMA模型实践总结
一、项目背景与目标 本文记录在天翼云昇腾910B服务器上部署DeepSeek 70B模型的全过程。该模型是基于LLaMA架构的知识蒸馏版本,模型大小约132GB。 1.1 硬件环境 - 服务器配置:天翼云910B服务器 - NPU:8昇腾910B (每卡64GB显存) - 系统内存&…...
Budibase低代码平台体验
低代码平台还是很多的,体验了Nocobase,又开始体验Budibase, 其实Budibase和appsmith更相似一点。 Budibase的安装也很简单。 1.安装好操作系统Debian; 2.安装好docker, docker-compose 3.创建目录/data,在里面参考内容创建文件docker-compos…...
【R语言】GitHub Copilot安装-待解决
参考: 文章目录...
Playwright 自动化测试系统学习
入门 Playwright安装:Playwright入门之---安装-CSDN博客 生成测试:Playwright入门之---生成测试-CSDN博客 命令汇总:Playwright入门之---命令-CSDN博客...
Jetson Agx Orin平台preferred_stride调试记录--1924x720图像异常
1.问题描述 硬件: AGX Orin 在Jetpack 5.0.1和Jetpack 5.0.2上测试验证 图像分辨率在1920x720和1024x1920下图像采集正常 但是当采集图像分辨率为1924x720视频时,图像输出异常 像素格式:yuv_uyvy16 gstreamer命令如下 gst-launch-1.0 v4l2src device=/dev/video0 ! …...
DeepSeek冲击(含本地化部署实践)
DeepSeek无疑是春节档最火爆的话题,上线不足一月,其全球累计下载量已达4000万,反超ChatGPT成为全球增长最快的AI应用,并且完全开源。那么究竟DeepSeek有什么魔力,能够让大家趋之若鹜,他又将怎样改变世界AI格…...
CF 144A.Arrival of the General(Java实现)
题目分析 一个n个身高数据,问最高的到最前面,最矮的到最后面的最短交换次数 思路分析 首先,如果数据有重复项,例如示例二中,最矮的数据就是最后一个出现的数据位置,最高的数据就是最先出现的数据位置&…...
set的使用(c++)
STL里面已经为我们实现了两种红黑树,一种是存储关键字的set,另一种是存储双关键字的map,今天主要来了解set,无论是set还是map后面都跟一个multi,它们区别是set 不能存相同元素, multiset 可以存相同的元素&…...
未加cont修饰的左值引用不能绑定到右值
目录 一、问题背景 二、错误分析 三、警告分析 一、问题背景 在initial value of reference to non-const - C Forum看到如下有问题的代码,编译如下代码看看 #include <iostream> #include <cmath>int g(double x) { return std::floor(x); } int&a…...
5.日常英语笔记
sprouted tater 发芽的土豆 fluid 液体,流体 The doctor recommended drinking plenty of fluids 医生建议多喝流质 适应新环境 adapt to the new environment adjust to the new surroundings get used to the new setting accommodate oneself to the new circu…...
IDEA单元测试插件 SquareTest 延长试用期权限
SquareTest是一款强大的IDEA单元测试生成插件工具,具体使用方法就不过多介绍了,这里主要介绍变更试用期,方便大家使用 配置信息 我的电脑安装前提配置条件 IntelliJ IDEA 2023.2windows 系统 软件安装 IntelliJ IDEA 直接安装插件Squar…...
25/2/17 <嵌入式笔记> 桌宠代码解析
这个寒假跟着做了一个开源的桌宠,我们来解析下代码,加深理解。 代码中有开源作者的名字。可以去B站搜着跟着做。 首先看下main代码 #include "stm32f10x.h" // Device header #include "Delay.h" #include &quo…...
C/C++字符串格式化全解析:从printf到std::format的安全演进与实战指南
目录 C 语言中的格式化函数对比 1. printf / fprintf / sprintf 的异同 C 中的字符串格式化 1. 流式输出 (std::ostringstream) 2. C20/23 格式化库 (std::format,需编译器支持) 跨语言对比与最佳实践 实战建议 总结 C 语言中的格式化函数对比 1. printf / …...
油田安全系统:守护能源生命线的坚固壁垒
油田安全系统:不可或缺的能源护盾 在能源领域,油田作为国家重要的能源供应基地,其安全生产的重要性不言而喻。油田安全系统犹如一道坚固的护盾,全方位守护着人员生命、企业财产以及生态环境,是油田平稳运行与可持续发展…...
【Python】实现文件移动与文件夹删除工具
【Python】 实现文件移动与文件夹删除工具 一、代码整体结构界面创建选择文件夹移动并删除操作处理文件重名问题打开文件夹 二、功能介绍三、 作者有话说 在日常的文件管理工作中,我们常常需要将某个文件夹下子文件夹中的文件统一移动到主文件夹,并删除这…...
LeetCode-680. 验证回文串 II
1、题目描述: 给你一个字符串 s,最多 可以从中删除一个字符。 请你判断 s 是否能成为回文字符串:如果能,返回 true ;否则,返回 false 。 示例 1: 输入:s "aba" 输出&a…...
【故障处理】- 执行命令crsctl query crs xxx一直hang
【故障处理】- 执行命令crsctl query crs xxx一直hang 一、概述二、故障处理三、解决方法 一、概述 Oracle RAC环境中,遇到执行crsctl query crs xxx等相关命令不返回任何结果,一直hang在那里。系统下执行命令ps -ef |grep crsctl query crs softwarever…...
JMeter工具介绍、元件和组件的介绍
Jmeter功能概要 JDK常用文件目录介绍 Bin目录:存放可执行文件和配置文件 Docs目录:是Jmeter的API文档,用于开发扩展组件 printable_docs目录:用户帮助手册 lib目录:存放JMeter依赖的jar包和用户扩展所依赖的Jar包…...
【Python 语法】Python 正则表达式(regular expressions, regex)
1. 基本语法1.1 字符匹配1.2 元字符1.3 特殊字符1.4 分组和捕获1.5 断言2. 常用函数2.1 `re.match()`2.2 `re.search()`2.3 `re.findall()`2.4 `re.sub()`2.5 `re.split()`3. 进阶用法3.1 捕获组3.2 非捕获组3.3 预查Python 中的**正则表达式(regular expressions, regex)**是…...
在 Python 里,None 可能是调用者主动传入的值,所以不能用 None 来判断参数是否被提供。
在 Python 里,None 可能是调用者主动传入的值,所以不能用 None 来判断参数是否被提供。 使用 object() 生成一个特殊的 唯一标记变量,用作默认参数的占位符,就可以明确区分调用者是否真的传递了这个参数。 📌 为什么 …...
DeepSeek 引领AI 大模型时代,服务器产业如何破局进化?
2025 年 1 月,DeepSeek - R1 以逼近 OpenAI o1 的性能表现,在业界引起轰动。其采用的混合专家架构(MoE)与 FP8 低精度训练技术,将单次训练成本大幅压缩至 557 万美元,比行业平均水平降低 80%。这一成果不仅…...
安卓burp抓包,bypass ssl pinning
好久好久没有发东西了。主要是懒。。。 这几天在搞apk渗透,遇到了burp无法抓包问题,觉得可以写下来。 问题描述 1. 一台安卓手机,装了面具,可以拿到root 2. 电脑上有burp,设置代理 3.手机和电脑连同一个网段&…...
服务器中部署大模型DeepSeek-R1 | 本地部署DeepSeek-R1大模型 | deepseek-r1部署详细教程
0. 部署前的准备 首先我们需要足够算力的机器,这里我在vultr中租了有一张A16显卡一共16GB显存的服务器作为演示。部署的模型参数为14b的。如果需要部署满血版本671b的,需要更大的算力支持,这里由于是个人资金有限,就演示14b的部署…...
rust学习笔记2-rust的包管理工具Cargo使用
首先先解决一个配置文件,目前rust版本升级后,config已经改成 config.toml 内容也做了如下调整 [source.crates-io] replace-with tuna[source.tuna] registry "https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git" 1.Rust 编程…...
DDD - 可能会用到的分布式事务
一、分布式事务的概念: 分布式事务是指跨越多个独立的资源或服务(例如多个数据库、微服务、消息队列等)执行的事务操作,其目标是确保整个事务在多个系统中保持原子性和一致性,即要么所有操作全部成功提交,…...
