首页 > 编程语言 >有向图的Tarjian算法

有向图的Tarjian算法

时间:2023-08-14 21:13:30浏览次数:31  
标签:连通 有向图 int Tarjian 算法 dfn low now 节点

强连通分量

对于一张有向图,对于图中任意两个节点\(x,y\),\(x\)能到\(y\),\(y\)也能到\(x\),则称其为强连通图。有向图的极大联通子图被称为强连通分量,简记为SCC(Strongly Connected Component)。

有时候,我们需要将一张有向图分成几个强连通分量,这时候可以基于Tarjian设计一个算法。

Tarjian求强连通分量

按照Tarjiand的惯例,我们需要对整个图进行一次dfs,将图的搜索树求出,设\(dfn_x\)为\(x\)节点最先遍历到的时间戳。

对于一个节点\(x\)来说,如果有一条边连接了它与它搜索树中的祖先\(fa_x\)(不仅是父亲),说明这个点可以与树上\(fa_x\)到\(x\)的路径组成环,而显然地一个环就是一个强连通子图,有助于我们寻找强连通分量。同理,如果有一点\(z\),它非\(x\)的祖先,但是它存在路径可以到达\(fa_x\),那连接\(x\)与\(z\)的边也很重要。

Tarjian维护了一个栈,栈中保存了\(x\)节点的祖先\(fa_x\),与已经访问过,并且存在一条路径到达\(x\)祖先的点。

接下来为了寻找到这些边,我们需要引入追溯值\(low_x\)。追溯值定义为满足以下条件的节点的最小时间戳:
1.该点在栈中。
2.存在一条从以\(x\)为跟的子树内出发指向\(x\)的有向边。

\(low_x\)的计算过程如下:
1.当节点\(x\)第一次访问时,将\(x\)入栈,并初始化\(low_x=dfn_x\).
2.遍历从\(x\)出发的每条边\((x,y)\):
(1).如果\(y\)未被访问,则\(y\)为\(x\)的子树内节点,它的追溯值可以更新\(low_x\),所以访问\(y\),回溯后令\(low_x=min(low_x,low_y)\)。
(2).若\(y\)被访问并且在栈内,则说明\(x\)可以到达这个节点后在回到自己,根据定义可以使\(low_x=min(low_x,dfn_y)\)。

下面我们来看一看如何分割强连通分量:
判定法则很简单:\(low_x=dfn_x\),则此时栈中从\(x\)到栈顶的所有节点构成一个强连通分量。

如果\(low_x=dfn_x\),那么说明\(x\)的子树内节点不能到达比\(x\)更早的节点再回到\(x\)(指时间戳更小),所以能形成的最大的强连通分量最大只包含了\(x\)。

以上便是\(Tarjian\)求强连通分量的主要流程。

实现

我们可以设\(ins_x=1\)表示\(x\)此刻是否在栈中,只在遍历边\((x,y)\)时\(y\)被访问过且\(ins_y=1\)时才将\(low_x\)更新为\(min(low_x,dfn_y)\),代表\(x\)可以去到\(y\)在回来。

接下来是tarjian代码:

int dfn[maxn],low[maxn],num;
int sta[maxn],top;
int ins[maxn],cou[maxn],cnt
void tarjian(int now) {
	dfn[now]=low[now]=++num;
	sta[++top]=now; ins[now]=1;
	for(int i=head[now];i;i=nex[i]) {
		int st=to[i];
		if(!dfn[st]) {
			tarjian(st);
			low[now]=min(low[now],low[st]);
		}
		else if(ins[st]) low[now]=min(low[now],dfn[st]);
	}
	if(dfn[now]==low[now]) {
		int x; cnt++;
		do {
			x=sta[top--];
			ins[x]=0; 
			cou[x]=cnt;
		} while(x!=now); 
	}
}

标签:连通,有向图,int,Tarjian,算法,dfn,low,now,节点
From: https://www.cnblogs.com/1n87/p/17629744.html

相关文章

  • 算法镇魂三部曲!
    一只小狐狸带你解锁炼丹术&NLP秘籍震惊!乐坛新人夕小瑶的卖萌屋今日重磅发布三张原创专辑!!????点击试听????点击试听????点击试听虽然卖萌屋常常被大家戏称为“仙女屋”、“神仙屋”、“宝藏屋”等,但卖萌屋更希望自己能成为一个有温度的创作小屋  小屋的每一位创作者,都跟小夕一样喜......
  • 2023-08-14:用go语言写算法。给出两个长度相同的字符串 str1 和 str2 请你帮忙判断字符
    2023-08-14:用go语言写算法。给出两个长度相同的字符串str1和str2,请你帮忙判断字符串str1能不能在零次或多次转化后变成字符串str2,每一次转化时,你可以将str1中出现的所有相同字母变成其他任何小写英文字母,只有在字符串str1能够通过上述方式顺利转化为字符串......
  • 2023-08-14:用go语言写算法。给出两个长度相同的字符串 str1 和 str2 请你帮忙判断字符
    2023-08-14:用go语言写算法。给出两个长度相同的字符串str1和str2,请你帮忙判断字符串str1能不能在零次或多次转化后变成字符串str2,每一次转化时,你可以将str1中出现的所有相同字母变成其他任何小写英文字母,只有在字符串str1能够通过上述方式顺利转化为字符串str2......
  • 敏感词过滤算法实现(前缀树)
    前缀树前缀树是N叉树的一种特殊形式,也叫Trie、字典树、查找树。通常来说,一个前缀树是用来存储字符串的。前缀树的每一个节点代表一个字符串(前缀)。每一个节点会有多个子节点,通往不同子节点的路径上有着不同的字符。子节点代表的字符串是由节点本身的原始字符串,以及通往该子节......
  • 类欧几里得算法
    类欧几里得算法定义\[\displaystyle\begin{aligned}f(a,b,c,n)&=\sum\limits_{i=0}^{n}\left\lfloor\dfrac{ai+b}{c}\right\rfloor\\g(a,b,c,n)&=\sum\limits_{i=0}^{n}{\left\lfloor\dfrac{ai+b}{c}\right\rfloor}^2\\h(a,b,c,n)&......
  • 编程题算法总结
    求最大公约数最小公倍数最大公约数辗转相除法大的a除小的b,得到余数如果是0,那么b就是最大公约数,否则就取余数做那个小的,本来的b就成了大的继续操作。intn,m;//辗转相除法,ab最大公约数=ab余数和b的最大公约数intyu,a,b;a=n>m?n:m;b=n>m?m:n......
  • 位运算 学习笔记【C++ 算法竞赛】
    大家好,欢迎来到我的第一篇博客位运算和移位运算作为计算机的基本运算之⼀,其都是对⼆进制位进⾏操作。作为近年算法竞赛笔试较热门的考点,它能够快捷地完成特定的应用。掌握它是⾮常有必要的。以下是目录:目录1.位运算的优先级2.左移运算<<、右移运算>>2.1运算规则:2.2应用:......
  • 路径规划算法:基于人工蜂鸟优化的机器人路径规划算法- 附matlab代码
    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。......
  • 路径规划算法:基于协作搜索优化的机器人路径规划算法- 附matlab代码
    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。......
  • 深入解析美颜SDK:算法、效果与实现
    在当今数字化社会中,图像处理和美化技术已经成为了许多应用领域的重要组成部分,尤其在视频直播领域,美颜技术更是无处不在。直播美颜SDK作为一种集成的软件工具包,为开发者和应用提供了强大的美颜功能。一、算法原理磨皮算法通过降低图像中的高频细节,达到皮肤更光滑的效果。美白算法调......