【蓝桥杯】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…

计算机基础系列 —— 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;使用…

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

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

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

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

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

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

Web API —— DOM 学习(四)(完结)

目录 一、日期对象 &#xff08;一&#xff09;实例化 &#xff08;二&#xff09;日期对象方法 1.时间戳介绍 2.获得时间戳的方式 getTime()方法 new Date()方法 Date.now()方法 二、节点操作 &#xff08;一&#xff09;DOM 节点 1.节点类型 元素节点 &#xff08…

1+x中级题目练习复盘(20220625 1+X 中级理论考试)

Override 用于标注重写方法 函数式接口是指有且只有一个抽象方法的接口&#xff1b;

vue项目使用eletron将打包成桌面应用(.exe)

vue项目使用eletron将打包成桌面应用(.exe) 1.前期准备 两个项目&#xff1a; 1、自己用vue cli创建的项目 2、第二个是去gitee将案例clone下来 案例地址 https://gitee.com/qingplus/electron-quick-start.git 2、测试案例是否可以正常运行 # 进入项目 cd electron-quick-…

任务管理工具Trello体验如何?一文揭秘

Trello是一款高效的协作与工作管理应用&#xff0c;这里我们将详细介绍Trello的功能、特点、优劣势、价格、定价、发展历程、使用场景以及使用技巧等等。 一、Trello 是什么 Trello是一款高效的协作与工作管理应用&#xff0c;设计用于跟踪团队项目、凸显当前活动任务、指派责…

POJ3037 + HDU-6714

两道最短路好题 POJ3037 手玩一下 发现每一点的速度可以直接搞出来&#xff0c;就是pow(2,h[1][1]-h[i][j])*V 那么从这个点出发到达别的点的耗费的时间都是上面这个数的倒数&#xff0c;然后直接跑最短路就好了 #include<iostream> #include<vector> #include<…

赛氪网积极参与千校万企协同创新行动,推动产学研深度融合

3月17日&#xff0c;中国千校万企协同创新推进会在北京盛大召开&#xff0c;会议旨在实现高校与行业龙头企业技术升级需求的精准对接&#xff0c;加速新质生产力的形成与发展。教育部党组成员、副部长孙尧&#xff0c;科技部成果转化司副司长秦浩源&#xff0c;国家知识产权局知…

王者荣耀国服米莱迪 - 出装打法详细教学视频(最新)

01. 恰到好处的一技能 02. 灵魂二技能 03. 无敌大招连招 04. 为所欲为的出装 05. 拥有这个召唤师技能赢一半 06. 英雄克制 07. 整局精讲 08. 米莱迪最强出装 09. 米莱迪最强出装的铭文 发送内容: "米莱迪", 获取提取码

【Java程序设计】【C00383】基于(JavaWeb)Springboot的水产养殖系统(有论文)

【C00383】基于&#xff08;JavaWeb&#xff09;Springboot的水产养殖系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;已经做了六年的毕业设计程序开发&#xff0c…