【蓝桥杯】tarjan算法

一.概述

Tarjan 算法是基于DFS的算法,用于求解图的连通性问题。

Tarjan 算法可以在线性时间内求出:

无向图:

  • 割点与桥
  • 双连通分量

有向图:

  • 强连通分量
  • 必经点与必经边

 1.割点:

若从图中删除节点 x 以及所有与 x 关联的边之后,图将被分成两个或两个以上的不相连的子图,那么称 x 为图的割点

2.割边/桥:

若从图中删除边 e 之后,图将分裂成两个不相连的子图,那么称 e 为图的割边

3.搜索树:

在无向图中,我们以某一个节点 x 出发进行深度优先搜索,每一个节点只访问一次,所有被访问过的节点与边构成一棵树,我们可以称之为“无向连通图的搜索树”。

4.时间戳:​

时间戳是用来标记图中每个节点在进行深度优先搜索被访问的时间顺序。

dfn[x] 来表示。

5.追溯值:

追溯值用来表示从当前节点 x 作为搜索树的根节点出发,能够访问到的所有节点中,时间戳最小的值 —— low[x]。

二.主要思想

主要思想:

通过一次深度优先遍历,即可找出有向图中的强连通分量。

深度优先遍历有两种方式:

  • 先访问当前节点,再递归相邻节点。
  • 先递归相邻节点,再访问当前节点。

数据结构分析:

  • 我们需要给每个节点一个时间戳,这个时间戳代表了该节点被访问的次序。
  • 同时,还需要一个记录该节点通过自身/子孙能够回到的最早的时间节点。

实现步骤:

  • 我们将所有节点的时间戳初始化为0,构建递归树。
  • 循环所有节点,若dfn[i]==0,则递归访问该节点。
  • 每次递归访问节点时,我们需要将该节点压栈,给时间戳和回溯值赋初值,同时遍历该节点的相邻节点,如果相邻节点的dfn为0,则其还没有被访问过,递归访问该节点,访问结束时,更新回溯值;如果相邻节点已经在栈中,那么就直接更新回溯值。另一种情况是,该节点已经被访问过,但是从栈中弹出,那么不做任何处理。
  • 当遍历完该节点的所有邻接点,我们要判断,该节点的时间戳的回溯值是否相等,若相等,则该节点为强连通分量的根节点。开始弹栈,直到将该节点弹出栈。

三.具体应用

1.求无向图的割边/割点

无向图最最重要的点在于,不能够去处理该节点通向父节点的那条边。

这是有向图和无向图最大的区别。

有向图需要去管在栈里的节点,看能否通过栈里面的节点回到更早的时间,但是为什么要用栈,就是因为一个节点只能访问一次;而对于无向图来说,当前正在访问的节点是通过该节点的父节点访问的,而无向图是不能访问子节点通过父节点的,所以不需要栈。

1)割点的判断方法

  • 该点是根节点并且该点有两个及以上的儿子
  • 该点不是根节点并且该点有儿子并且该点儿子的追溯值大于或等于该点被访问的时间

//tarjan求无向图的割点
#include <iostream>
#include <cstring>
#include <vector>using namespace std;
const int N=100000;//链式前向星,用来表示边
struct node{int to,next;
}edge[N];
int head[N]={-1},cnt=1;//head[i]表示的是以节点i为始点的边,head[i]中的值表示的是第几条边int time_flag=0,n,m,res=0,root;
int dfn[N]={0},low[N]={0};//dfn时间戳,low追溯值
bool is_articulation[N]={false};//是否是割点//加边
void add(int u,int v){edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;
}void tarjan(int u){dfn[u]=low[u]=++time_flag;int child=0;int v=head[u];while(v!=-1){int a=edge[v].to;if(dfn[a]==0){child++;tarjan(a);low[u]=min(low[u],low[a]);if((u==root&&child>1)||(u!=root&&low[a]>=dfn[u])){if(!is_articulation[u]){is_articulation[u]=true;res++;}}}else{low[u]=min(low[u],dfn[a]);}v=edge[v].next;}}int main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n>>m;//n个顶点,m条边//构建好无向图,顶点和边的下标都是从1开始memset(head,-1,sizeof(head));for(int i=0;i<m;i++){int x,y;cin>>x>>y;add(x,y);add(y,x);}for(int i=1;i<=n;i++){if(!dfn[i]){root=i;tarjan(i);}}cout<<res<<'\n';for(int i=1;i<=n;i++){if(is_articulation[i])cout<<i<<' ';}cout<<'\n';return 0;
}

 

2)割边的判断方法

若x->y这条边是割边,那么low[y]>dfn[x] 

2.求强连通分量(有向图)

//tarjan求强连通分量
#include <iostream>
#include <stack>using namespace std;
const int N=100;//链式前向星,用来表示边
struct node{int to,next;
}edge[N];
int head[N]={-1};//head[i]表示的是以节点i为始点的边,head[i]中的值表示的是第几条边int time_flag=0,n,m,cnt=0;
int dfn[N]={0},low[N]={0};//dfn时间戳,low追溯值
bool instack[N]={false};
stack<int> s;//加边
void add(int u,int v){edge[cnt].to=v;edge[cnt].next=head[u];head[u]=++cnt;
}void tarjan_dfs(int u){dfn[u]=low[u]=++time_flag;//时间戳和追溯值赋初值s.push(u);//节点入栈instack[u]=true;int v=head[u];while(v!=-1){//找与u邻接的边int a=edge[v].to;if(!dfn[a]){//a还没有被访问过tarjan_dfs(a);//深度优先访问a节点low[u]=min(low[a],low[u]);}else if(instack[a]){//v已经被访问过low[u]=min(dfn[a],low[u]);}v=edge[v].next;}if(low[u]==dfn[u]){//表明节点u是强连通分量的根int x;do{x=s.top();cout<<x<<' ';s.pop();instack[x]={false};}while(x!=u);cout<<endl;}
}
int main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n>>m;//n个顶点,m条边//构建好有向图,顶点和边的下标都是从1开始for(int i=0;i<m;i++){int x,y;cin>>x>>y;add(x, y);}for(int i=1;i<=n;i++){if(!dfn[i]){tarjan_dfs(i);}}return 0;
}

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

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

相关文章

Intel AIPC发布会:开启AI终端应用的新纪元

2024年3月27日下午&#xff0c;Intel在北京市朝阳区凤凰中心举办了AIPC发布会开启了AI终端应用的新征程。 整场发布会围绕着‘让不可想象&#xff0c;变为寻常’主线进行。在本次发布会上&#xff0c;众多PC端的AI应用得到了展示&#xff0c;包括&#xff1a;智谱AI&#xff…

第十一届蓝桥杯大赛第二场省赛试题 CC++ 研究生组-寻找2020

数据很恶心&#xff0c;但是考点挺友好~ 把测试数据黏贴到记事本中&#xff0c;知测试数据的行列数 然后根据规则判断2020是否出现&#xff0c;并累计其次数即可。 判断可能需要注意超出下标&#xff0c;可以索性把数组定大些。 #include<stdio.h> const int N 310; ch…

哈曼卡顿音箱解决关闭自动休眠 + 自用车载音乐分享制作

一&#xff1a;哈曼卡顿音箱解决关闭自动休眠 1. 背景&#xff1a;每天做最多的事情就是开音箱电源。问了客服&#xff0c;说只有玻璃4才能关闭休眠。搞得我都想买新音箱了。 2. 解决办法&#xff1a;电脑开机启动一个阻止功放休眠.exe&#xff0c;可以设置自动启动&#x…

Redis入门到实战-第十九弹

Redis实战热身Count-min-sketch篇 完整命令参考官网 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息为准 https://redis.io/Redis概述 Redis是一个开源的&#xff08;采用BSD许可证&#xff09;&#xff0c;用作数据库、缓存、…

Android Studio 无法下载 gradle-7.3.3-bin.zip

下载新的Android Studio&#xff0c;然后创建新的工程时&#xff0c;出现报错&#xff1a;Could not install Gradle distribution from https://services.gradle.org/distributions/gradle-7.3.3-bin.zip 或者超时&#xff0c;我们可以复制&#xff1a;https://services.grad…

IntellIJ Idea 内存不足时怎么设置

文章目录 前言背景一、 内存显示二、 在IDEA中设置内存三 、在IDEA中打开内存的设置文件四、 JetBrains ToolBox 中安装 IntellIJ Idea配置文件位置总结 前言 请各大网友尊重本人原创知识分享&#xff0c;谨记本人博客&#xff1a;南国以南i、 提示&#xff1a;以下是本篇文章…

【React】react 使用 lazy 懒加载模式的组件写法,外面需要套一层 Loading 的提示加载组件

react 组件按需加载问题解决 1 错误信息2 解决方案 1 错误信息 react 项目在创建 router 路由时&#xff0c;使用 lazy 懒加载时&#xff0c;导致以下报错&#xff1a; The above error occurred in the <Route.Provider> component:Uncaught Error: A component suspe…

qiankun实现基座、子应用样式隔离

目录 qiankun 实现主应用与子应用样式隔离使用CSS-in-JS来实现样式隔离react-jssstyled-components qiankun 实现主应用与子应用样式隔离 qiankun 之中默认的样式隔离是针对子应用与子应用之间的。至于主应用的样式会影响到子应用&#xff0c;若需要&#xff0c;则需要配置进行…

计算机基础系列 —— CPU

“Make everything as simple as possible, but no simpler.” – Albert Einstein 文中提到的所有实现都可以参考&#xff1a;nand2tetris_sol&#xff0c;但是最好还是自己学习课程实现一遍&#xff0c;理解更深刻。 之前的文章里我们介绍了 Register、PC、RAM 和 ALU&#…

【Linux实践室】Linux用户管理实战指南:用户密码管理操作详解

&#x1f308;个人主页&#xff1a;聆风吟_ &#x1f525;系列专栏&#xff1a;Linux实践室、网络奇遇记 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 一. ⛳️任务描述二. ⛳️相关知识2.1 &#x1f514;用户密码存放地及方式2.2 &#x1f514;使用…

PAT乙级 1046 划拳 C语言实现

划拳是古老中国酒文化的一个有趣的组成部分。酒桌上两人划拳的方法为&#xff1a;每人口中喊出一个数字&#xff0c;同时用手比划出一个数字。如果谁比划出的数字正好等于两人喊出的数字之和&#xff0c;谁就赢了&#xff0c;输家罚一杯酒。两人同赢或两人同输则继续下一轮&…

游戏本续航@控制中心的省电模式效果如何

文章目录 节能模式长续航模式&#x1f47a;相关工具 节能模式长续航模式&#x1f47a; 蓝天模具Control Center中的模式 根据我的试验,以及软件的提示,可以发现 Power Saving是最省电的,儿Quiet模式并不省电,它会启用独立显卡,只不过风扇的转速不像娱乐模式和性能模式那么积极而…

UE5学习日记——蓝图节点前缀关键字整理

一、起因 节点如海&#xff0c;中英文翻译的时候还是有差别的&#xff0c;比如&#xff1a; 同一个中文&#xff0c;可能在英文里完全不同&#xff0c;连出现位置可能都不一样 附加 Attach Actor To Component&#xff08;将Actor附加到组件&#xff09;Append Array&#xf…

mac 配置 ssh

mac 系统如何生成秘钥的方法 【第一步】. 启动台打开终端&#xff0c;输入 cd ~/.ssh 检查是否已经存在了SSH密钥。如果你看到类似id_rsa.pub的文件&#xff0c;说明你已经有了一对公钥和私钥&#xff0c;可以跳过第 2 步和第 3 步。 【第二步】 在终端输入ssh-keygen -t rsa …

1.3-数组-977. 有序数组的平方★

977. 有序数组的平方 ★ 力扣题目链接&#xff0c;给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 1 < nums.length < 104-104 < nums[i] < 104nums 已按 非递减顺序 排序 示例…

如何结合NLP和图像描述技术

结合自然语言处理&#xff08;NLP&#xff09;和图像描述技术的例子有很多&#xff0c;以下是一些具体的应用场景&#xff1a; 1. **自动图像描述生成器**&#xff1a; - 用户上传一张图片到应用程序。 - 应用程序使用计算机视觉技术分析图片内容。 - NLP算法如序列到…

Python中模块的定义、用法

在Python中&#xff0c;模块是一个包含了Python代码的文件。模块可以包含变量定义、函数、类等&#xff0c;并且可以在其他Python脚本中被导入和使用。模块的定义和用法如下所示&#xff1a; 模块的定义&#xff1a; 创建模块文件&#xff1a;在Python中&#xff0c;一个模块就…

数据分析和机器学习库Pandas的使用

Pandas 库是一个免费、开源的第三方 Python 库&#xff0c;是 Python 数据分析和机器学习的工具之一。Pandas 提供了两种数据结构&#xff0c;分别是 Series&#xff08;一维数组结构&#xff09;与 DataFrame&#xff08;二维数组结构&#xff09;&#xff0c;极大地增强的了 …

ubuntu18.04安装docker 并修改其默认路径

ubuntu18.04安装docker 并修改其默认路径 0 删除已有docker sudo apt-get remove docker docker-engine docker.io containerd runc1 使用 Docker 仓库进行docker安装 两个方法可以较差借鉴用 方法一&#xff08;实测成功&#xff09;&#xff1a; 参考链接&#xff1a;ht…

文件路径中的 ./ 和 ../ 和 / 的区别

路径中的“./”、“../”和“/”分别代表以下含义&#xff1a; “./”&#xff1a;代表当前所在的目录。在路径中使用它&#xff0c;表示你正在引用当前目录下的一个文件或子目录。“../”&#xff1a;代表上一层目录。当你在路径中使用“../”&#xff0c;你正在引用当前目录…