C++算法篇:DFS超详细解析(2)--- tarjan算法求无向图割边
2021/10/20 20:39:56
本文主要是介绍C++算法篇:DFS超详细解析(2)--- tarjan算法求无向图割边,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
<<<上一篇
系列文章目录
①:无向图基本概念
②:tarjan算法求无向图割边
前言
第一次写算法,讲得肯不透彻,有误还请指教awa
文章目录
- 系列文章目录
- 一、回顾
- 二、tarjan算法
- 2.1、求割边并输出
- 2.2、求连通分量
一、回顾
先来回顾一下dfs的基本框架:
//存图方式:vector(g[N]) void dfs(int u){//u:当前节点 vis[u]=true; for(int& v:g[u]){//访问u连到的每个节点 if(!vis[v]) dfs(v); } }
二、tarjan算法
请注意,这里讲的仅限于无向图,有向图的算法会稍有不同。
- 首先我们可以确定的是回边一定不是桥1。
- 那么就只需要判断树边了。
回顾割边的定义,删边后两端断开,那么就意味着一端的点永远无法通过一条路径回到另一端,在DFS-tree上就体现为下方的节点永远无法通过非树边回到上方的点。如果成立,即只能通过树边相连,那么这条树边就是桥了!(因为是树,每个节点以自己为终点只会有一个直系父亲)
tarjan算法定义了两个数组:depth[]
和low[]
,定义如下:
depth[i]
:节点i在DFS-tree上的深度。low[i]
:在dfs-tree上,以节点i及其子孙为起点的回边回到的 最低 高度。
假设我们已经算出每个节点的depth
(下简称dep
)和low
,如何判断割边呢?
(务必注意,dep
和low
越大意味着越晚被遍历)
分类讨论一下吧:(假设目前在处理tree2上u->v边)
-
l o w [ v ] < = d e p [ u ] low[v]<=dep[u] low[v]<=dep[u]:意味着v(下方点)能回到u(上)及u以上的点,此时拿掉u-v,仍有至少1条路径使v能回溯到上面,不会断开,故不是桥。
-
l o w [ v ] > d e p [ u ] low[v]>dep[u] low[v]>dep[u]:意味着v只能回到u以下,此时若拿掉u-v,u、v间回断开,故是桥。
(很久以前的笔记)
至此,我们已经明确割边的判断,最后一件事便是求low
值 了:
- 未访问过的点(树边):那么这是原节点的子孙,只需在dfs改点后将二者low取min(因为存在下方没有树边的情况此时不需更新low)
- 已访问的点(回边):(边u->v)取low[u]=min(low[u],dep[v]),注意回边终点用dep而非low,因为low去的时候回到的最早,不能二次回边。
2.1、求割边并输出
//vector<> g存图 int d=0;//深度从0开始 void dfs(int u){ vis[u]=1; dep[u]=low[u]=d++; for(int i=0;i<g[u].size();++i){ int& v=g[u][i]; if(!vis[u]){//树边 dfs(v); low[u]=min(low[u],low[v]);//更新 low[]值 //仅在是树边时判断 if(low[u]>dep[v]) printf("%d-%d\n",u,v); } else{//回边 low[u]=min(low[u],dep[v]); } } }
2.2、求连通分量
//求图的连通分量 int st[N],tp=0;//栈 int cn;//分量数量 int d=0; void dfs(int u){ vis[u]=1; dep[u]=low[u]=d++; st[tp++]=u;//入栈 for(int i=0;i<g[u].size();++i){ int& v=g[u][i]; if(!vis[u]){ dfs(v); low[u]=min(low[u],low[v]); if(low[u]>dep[v]){ printf("第%d个连通分量:",++cn); int t; do{ t=st[tp--]; printf("%d ",t); }while(t!=u); printf("\n"); } } else{ low[u]=min(low[u],dep[v]); } } return; } #if 0 算法实现:若u->v是桥,则当前栈出到v(v出)。 #endif
顺带一提,边-2-连通图 指至少删掉2条边才不连通(即无桥)。
THANK YOU !
证明:
因为是无向图,所以dfstree上的有向边在原图上无向,那么dfstree底图上回边形成的环在原图也是成立的,那么对于环上的任意u,v,都至少有2条路径互通,拿掉一条后至少剩一条,所以回边不是桥。
如图: ↩︎即DFS-tree,下同。 ↩︎
这篇关于C++算法篇:DFS超详细解析(2)--- tarjan算法求无向图割边的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23增量更新怎么做?-icode9专业技术文章分享
- 2024-11-23压缩包加密方案有哪些?-icode9专业技术文章分享
- 2024-11-23用shell怎么写一个开机时自动同步远程仓库的代码?-icode9专业技术文章分享
- 2024-11-23webman可以同步自己的仓库吗?-icode9专业技术文章分享
- 2024-11-23在 Webman 中怎么判断是否有某命令进程正在运行?-icode9专业技术文章分享
- 2024-11-23如何重置new Swiper?-icode9专业技术文章分享
- 2024-11-23oss直传有什么好处?-icode9专业技术文章分享
- 2024-11-23如何将oss直传封装成一个组件在其他页面调用时都可以使用?-icode9专业技术文章分享
- 2024-11-23怎么使用laravel 11在代码里获取路由列表?-icode9专业技术文章分享
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享