Tarjan算法求桥 思路+代码 无向图

目录几个定义桥深度优先数dfn直接父节点祖先子孙最小可达祖先Tarjan算法求解思路证明:伪代码图解代码几个定义桥桥是特殊的边,一个桥连接两个不同的连通分量,当一条边被去掉的时候,整个图的连通分量个数增加深度优先数dfndfn[] 即 depth first number ,深度优先数,dfn[x] 表示 x 号节点被访问的顺序,也就是dfs的顺序,如图,假设从左上角节点开始dfs,蓝色数字就是对应节点的dfn直接父节点如果dfs的其中一次递归有这样的顺序 A->B 那么A是B的直接
摘要由CSDN通过智能技术生成

几个定义

桥是特殊的边,一个桥连接两个不同的连通分量,当一条边被去掉的时候,整个图的连通分量个数增加
在这里插入图片描述

深度优先数dfn

dfn[] 即 depth first number ,深度优先数,dfn[x] 表示 x 号节点被访问的顺序,也就是dfs的顺序,如图,假设从左上角节点开始dfs,蓝色数字就是对应节点的dfn
在这里插入图片描述

直接父节点

如果dfs的其中一次递归有这样的顺序 A->B 那么A是B的直接父节点

祖先

任何满足dfn[v] < dfn[x]v 不是 x 的直接父节点 的节点 v,都是 x 的祖先

子孙

任何满足 dfn[v] > dfn[x] 的节点 v,都是 x 的子孙

最小可达祖先

min_ancestor[] 即 ”最小可达祖先“ ,min_ancestor[x] 表示 x 及其所有子孙)能够到达的,dfn数值最小(即最老,最先被访问)的祖先节点(不包括x的直接父节点)的dfn值

Tarjan算法求解思路

使用Tarjin算法求解桥,需要基于dfs,而在dfs的同时,我们需要维护两个数组

  1. dfn[] 即 depth first number ,深度优先数,dfn[x] 表示 x 号节点被访问的顺序,也就是dfs的顺序
  2. min_ancestor[] 即 ”最小可达祖先“ ,min_ancestor[x] 表示 x
    及其所有子孙
    能够到达的,dfn数值最小(即最老,最先被访问的祖先)的节点的dfn值

如果存在一条边 v1 -- v2,使得 dfn[v1] < min_ancestor[v2] 那么这条边是桥

证明:

dfn表示dfs遍历的顺序,而min_ancestor[v2] > dfn[v1] 表示 v2 的任意子孙,除了通过 v2--v1 这条边,没有其他途径可以到达v1

(因为v2任意子孙可达的最早节点,其dfn都大于dfn[v1],也就是说子孙们最早只能到v2,不能到v1)

在这里插入图片描述

伪代码

  • 对节点x进行dfs,同时记录x的直接父节点father
  • dfn[x] = min_ancestor[x] = 当前dfs进行步数
  • 遍历x的所有邻接节点,这些邻接节点暂时叫做child
  • 如果child还没被访问,那么他是子孙节点,先对child递归dfs,然后尝试更新x的最小可达祖先,即min_ancestor[x] = min(min_ancestor[x], min_ancestor[child])
  • 如果child已经被访问,且child不是x的直接父节点,那么child是x的祖先,这时候我们发现可以到达祖先,那么记录祖先的dfn值,并且尝试更新x的最小可达祖先,即 min_ancestor[x] = min(min_ancestor[x], dfn[child])

图解

在这里插入图片描述

代码

第一行输入顶点数,然后一直输入边 v1 v2 顶点编号(从0开始),直到输入 -1 -1 结束
在这里插入图片描述

#
  • 10
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: ```python class Tarjan: def __init__(self, graph): self.graph = graph self.index = 0 self.stack = [] self.visited = [False for _ in range(graph.num_vertices)] self.indices = [-1 for _ in range(graph.num_vertices)] self.low_link_values = [-1 for _ in range(graph.num_vertices)] self.on_stack = [False for _ in range(graph.num_vertices)] self.scc = [] def is_cyclic(self): for vertex in range(self.graph.num_vertices): if not self.visited[vertex]: self.strongconnect(vertex) return any(len(x) > 1 for x in self.scc) def strongconnect(self, vertex): self.visited[vertex] = True self.indices[vertex] = self.index self.low_link_values[vertex] = self.index self.index += 1 self.stack.append(vertex) self.on_stack[vertex] = True for neighbor in self.graph.get_adjacent_vertices(vertex): if not self.visited[neighbor]: self.strongconnect(neighbor) self.low_link_values[vertex] = min(self.low_link_values[vertex], self.low_link_values[neighbor]) elif self.on_stack[neighbor]: self.low_link_values[vertex] = min(self.low_link_values[vertex], self.indices[neighbor]) if self.low_link_values[vertex] == self.indices[vertex]: scc = set() while True: w = self.stack.pop() self.on_stack[w] = False scc.add(w) if w == vertex: break self.scc.append(scc) ``` 上面是Tarjan算法查找无向图中环的Python代码。使用时,需要传入一个图对象,然后调用is_cyclic()方法,如果返回值为True,则说明图中存在环。 注意,这段代码需要图数据结构的支持,图的实现可以自己实现或者使用第三方库如networkx。 ### 回答2: Tarjan算法是一种强连通分量算法,可以用于在无向图中查找环。下面是用Python实现Tarjan算法代码: ```python class Graph: def __init__(self, num_vertices): self.num_vertices = num_vertices self.adj_list = [[] for _ in range(num_vertices)] self.visited = [False] * num_vertices self.low = [0] * num_vertices self.ids = [0] * num_vertices self.id = 0 self.result = [] def add_edge(self, u, v): self.adj_list[u].append(v) self.adj_list[v].append(u) def tarjan(self, v, parent): self.visited[v] = True self.low[v] = self.ids[v] = self.id self.id += 1 for neighbor in self.adj_list[v]: if neighbor == parent: continue if not self.visited[neighbor]: self.tarjan(neighbor, v) self.low[v] = min(self.low[neighbor], self.low[v]) if self.low[neighbor] > self.ids[v]: self.result.append((v, neighbor)) else: self.low[v] = min(self.low[v], self.ids[neighbor]) def find_cycles(self): for i in range(self.num_vertices): if not self.visited[i]: self.tarjan(i, -1) if len(self.result) == 0: print('The graph does not contain any cycles.') else: print('The cycles in the graph are:') for cycle in self.result: print(cycle) g = Graph(5) g.add_edge(0, 1) g.add_edge(1, 2) g.add_edge(2, 3) g.add_edge(3, 0) g.add_edge(2, 4) g.find_cycles() ``` 以上代码实现了一个`Graph`类,包含了添加边、Tarjan算法等功能。通过调用`find_cycles`方法可以找到给定无向图中的所有环。在测试代码中,创建了一个包含5个顶点的无向图,并添加了若干条边。通过调用`find_cycles`方法,将打印出图中的所有环。如果图中不包含任何环,则会打印出相应的提示信息。 ### 回答3: Tarjan算法是一种用于查找无向图中环的强大算法。它通过遍历图中的每个节点,深度优先搜索子节点,并利用栈来维护当前遍历路径的节点。具体的Python实现如下: ```python class Graph: def __init__(self, vertices): self.V = vertices self.adj = [[] for _ in range(vertices)] self.Index = [-1] * vertices self.Lowlink = [-1] * vertices self.OnStack = [False] * vertices self.stack = [] self.count = 0 def addEdge(self, u, v): self.adj[u].append(v) self.adj[v].append(u) def tarjan(self, u, parent): self.Index[u] = self.count self.Lowlink[u] = self.count self.count += 1 self.stack.append(u) self.OnStack[u] = True for v in self.adj[u]: if v == parent: continue if self.Index[v] == -1: self.tarjan(v, u) self.Lowlink[u] = min(self.Lowlink[u], self.Lowlink[v]) elif self.OnStack[v]: self.Lowlink[u] = min(self.Lowlink[u], self.Index[v]) if self.Lowlink[u] == self.Index[u]: w = -1 while w != u: w = self.stack.pop() self.OnStack[w] = False print(w, end=" ") print() def findCycle(self): for i in range(self.V): if self.Index[i] == -1: self.tarjan(i, -1) # 测试样例 g = Graph(5) g.addEdge(1, 0) g.addEdge(0, 2) g.addEdge(2, 1) g.addEdge(0, 3) g.addEdge(3, 4) print("无向图中的环为:") g.findCycle() ``` 这段代码首先定义了一个Graph类来表示无向图,其中包括图的顶点数和邻接列表。在tarjan函数中,使用了Index、Lowlink和OnStack列表来记录每个节点的索引、最低链接值以及是否在栈中。遍历节点时,使用递归进行深度优先搜索,并根据Index和Lowlink值来判断是否找到环。在findCycle函数中,遍历图中的每个节点,对没有被访问过的节点调用tarjan函数进行环的查找。最后的测试样例中,创建了一幅无向图,然后调用findCycle函数查找环,并输出结果。 希望这段代码能够帮助你理解Python实现的Tarjan算法,并在无向图中查找环的过程中能够起到指导作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值