Tarjan 算法

本蒟蒻第一次写博客,不喜勿喷

什么是 Tarjan 算法呢? 

让我们来看一张有向图:

首先,我们要知道  dfs序  是什么(应该都知道吧)。

顾名思义,dfs序 就是一张图在进行 dfs 时所经历的点的先后排序。

详见:dfs序(基础讲解)_不牌不改的博客-CSDN博客_dfs序

(借用,如有侵权请联系删除)。

再一个,我们要知道 强联通, 强项通图, 强联通分量  是什么。

强联通:强连通是指一个有向图G中,任意两点v1、v2间存在v1到v2的路径, 以及v2到v1的路径。
强连通图: 如果 在一个有向图G中,每两个点都强连通,我们就叫这个图强连通图

强连通分量:有向图的所有强连通子图

tarjan算法,用dfs就是因为它将每一个强连通分量作为搜索树上的一个子树。
两个参数:
1,dfn[]作为这个点搜索的次序编号,简单来说就是 第几个被搜索到的。
2,low作为每个点在这颗树中的,最小的子树的根,每次保证最小。如果它自己的low[]最小,那这个点就应该重新分配,变成这个强连通分量子树的根节点

而为了存储整个强连通分量,这里挑选的容器是,堆栈。每次一个新节点出现,就进站,如果这个点有 出度 就继续往下找。直到找到底,每次返回上来都看一看子节点与这个节点的low值,谁小就取谁,保证最小的子树根。如果找到dfn[] == low[]就说明这个节点是这个强连通分量的根节点。最后找到强连通分量的节点后,就将这个栈里,比此节点后进来的节点全部出栈,它们就组成一个全新的强连通分量

上代码:

void tarjan(int u) {
	dfn[u] = low[u] = ++ num;
	stack[++top] = u;
	ins[u] = 1;
	for (int i = head[u]; i; i = edge[i].nxt) {
		int v = edge[i].v;
		if(!dfn[v]) {
			tarjan(v);
			low[u] = min(low[u], low[v]);
		}
		else if(ins[v]) {
			low[u] = min(low[u], loe[v]);
		}
	}
	if(dfn[u] == low[u]) {
		cnt++;
		int v;
		do {
			v = stack[top]--;
			ins[v] = 0;
			c[v] = cnt;
			scc[cnt].push_back(v);
		} while(u != v);
	}
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
LCA(最近公共祖先)是指在一棵树中,找到两个节点的最近的共同祖先节点。而Tarjan算法是一种用于求解强连通分量的算法,通常应用于有向图中。它基于深度优先搜索(DFS)的思想,通过遍历图中的节点来构建强连通分量。Tarjan算法也可以用于求解LCA问题,在有向无环图(DAG)中。 具体来说,在使用Tarjan算法求解LCA时,我们需要进行两次DFS遍历。首先,我们从根节点开始,遍历每个节点,并记录每个节点的深度(即从根节点到该节点的路径长度)。然后,我们再进行一次DFS遍历,但这次我们在遍历的过程中,同时进行LCA的查找。对于每个查询,我们将两个待查询节点放入一个查询列表中,并在遍历过程中记录每个节点的祖先节点。 在遍历的过程中,我们会遇到以下几种情况: 1. 如果当前节点已被访问过,说明已经找到了该节点的祖先节点,我们可以更新该节点及其所有后代节点的祖先节点。 2. 如果当前节点未被访问过,我们将其标记为已访问,并将其加入到查询列表中。 3. 如果当前节点有子节点,我们继续递归遍历子节点。 最终,对于每个查询,我们可以通过查询列表中的两个节点的最近公共祖先节点来求解LCA。 需要注意的是,Tarjan算法的时间复杂度为O(V+E),其中V为节点数,E为边数。因此,对于大规模的树结构,Tarjan算法是一种高效的求解LCA问题的方法。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值