铰接点算法-后边缘识别

问题描述 投票:4回答:1

我正在研究Tarjan的算法,该算法使用DFS查找图形中的铰接点。

https://www.geeksforgeeks.org/articulation-points-or-cut-vertices-in-a-graph/

某些符号:

low[] : It is an array of N elements which stores the discovery time of every vertex. It is initialized by 0.

disc[]: It is an array of N elements which stores, for every vertex v, the discovery time of the earliest discovered vertex to which v or any of the vertices in the subtree rooted at v is having a back edge. It is initialized by INFINITY.

现在是算法:

from collections import defaultdict 

#This class represents an undirected graph 
#using adjacency list representation 
class Graph: 

    def __init__(self,vertices): 
        self.V= vertices #No. of vertices 
        self.graph = defaultdict(list) # default dictionary to store graph 
        self.Time = 0

    # function to add an edge to graph 
    def addEdge(self,u,v): 
        self.graph[u].append(v) 
        self.graph[v].append(u) 

    '''A recursive function that find articulation points 
    using DFS traversal 
    u --> The vertex to be visited next 
    visited[] --> keeps tract of visited vertices 
    disc[] --> Stores discovery times of visited vertices 
    parent[] --> Stores parent vertices in DFS tree 
    ap[] --> Store articulation points'''
    def APUtil(self,u, visited, ap, parent, low, disc): 

        #Count of children in current node 
        children =0

        # Mark the current node as visited and print it 
        visited[u]= True

        # Initialize discovery time and low value 
        disc[u] = self.Time 
        low[u] = self.Time 
        self.Time += 1

        #Recur for all the vertices adjacent to this vertex 
        for v in self.graph[u]: 
            # If v is not visited yet, then make it a child of u 
            # in DFS tree and recur for it 
            if visited[v] == False : 
                parent[v] = u 
                children += 1
                self.APUtil(v, visited, ap, parent, low, disc) 

                # Check if the subtree rooted with v has a connection to 
                # one of the ancestors of u 
                low[u] = min(low[u], low[v]) 

                # u is an articulation point in following cases 
                # (1) u is root of DFS tree and has two or more chilren. 
                if parent[u] == -1 and children > 1: 
                    ap[u] = True

                #(2) If u is not root and low value of one of its child is more 
                # than discovery value of u. 
                if parent[u] != -1 and low[v] >= disc[u]: 
                    ap[u] = True    

                # Update low value of u for parent function calls    
            elif v != parent[u]: 
                low[u] = min(low[u], disc[v]) 


    #The function to do DFS traversal. It uses recursive APUtil() 
    def AP(self): 

        # Mark all the vertices as not visited 
        # and Initialize parent and visited, 
        # and ap(articulation point) arrays 
        visited = [False] * (self.V) 
        disc = [float("Inf")] * (self.V) 
        low = [float("Inf")] * (self.V) 
        parent = [-1] * (self.V) 
        ap = [False] * (self.V) #To store articulation points 

        # Call the recursive helper function 
        # to find articulation points 
        # in DFS tree rooted with vertex 'i' 
        for i in range(self.V): 
            if visited[i] == False: 
                self.APUtil(i, visited, ap, parent, low, disc) 

        for index, value in enumerate (ap): 
            if value == True: print index, 

# Create a graph given in the above diagram 
g1 = Graph(5) 
g1.addEdge(1, 0) 
g1.addEdge(0, 2) 
g1.addEdge(2, 1) 
g1.addEdge(0, 3) 
g1.addEdge(3, 4) 

print "\nArticulation points in first graph "
g1.AP() 

g2 = Graph(4) 
g2.addEdge(0, 1) 
g2.addEdge(1, 2) 
g2.addEdge(2, 3) 
print "\nArticulation points in second graph "
g2.AP() 


g3 = Graph (7) 
g3.addEdge(0, 1) 
g3.addEdge(1, 2) 
g3.addEdge(2, 0) 
g3.addEdge(1, 3) 
g3.addEdge(1, 4) 
g3.addEdge(1, 6) 
g3.addEdge(3, 5) 
g3.addEdge(4, 5) 
print "\nArticulation points in third graph "
g3.AP() 

#This code is contributed by Neelam Yadav 

在此算法中,关注的线是:

low[u] = min(low[u], low[v]) 

此行很容易理解。通过后端连接到u的最早发现顶点=通过后端连接到其任何子节点(v)的最早发现顶点

确定。现在基本条件?

elif v != parent[u]:  
    low[u] = min(low[u], disc[v]) 

这也很容易理解:如果连接到u的顶点v已被访问(检查此elif对应的if条件)并且“ v”不是u的父对象,则更新low [u]以包括disc [v]。

现在我的问题:

仅仅因为v已经被访问过,所以您知道边缘(u,v)不是树的边缘。但是您如何确定这是一个后缘呢?根据Tarjan的算法:

low [u] = min(disc [u],disc [w])],其中w是u的祖先是从u的后代到w的后边缘。

如果不是树边缘,则可以是前边缘,后边缘或交叉边缘。要从这三种类型的边中识别出后边,我们需要每个顶点的开始时间和结束时间。我们在这里不做任何检查。那么,我们如何假设所做的更新确实使用了后端?

python algorithm data-structures graph depth-first-search
1个回答
0
投票

您是正确的,在有向图图中,有四种类型的边:树形,后边,前向和交叉边。 Wikipedia具有简要定义和说明图。但是,在无向图中,只有树和后边缘。为什么会这样?

  • 前边缘(上面链接中的1-8):在有向图中,让我们考虑前边缘(uv)。 DFS算法首先访问u,然后通过其他路径(在上面的链接中为1-5-6-8)到达v,从该路径返回,然后考虑边缘(u] >,v)并说:“哦,我已经访问过[[v;从发现/完成时间开始,我可以看到vu的后代,这意味着(uv)是前缘。”但是在无向图中,在访问节点v时,首先将边缘(uv)视为inverse,因此它成为后边缘( vu)。交叉边缘(上面链接中的6-3):通过类似的过程,有向图中的交叉边缘(
  • u
  • v)将在无向图中被反向发现,并变为树边缘(vu)。在示例中,我们从节点3访问节点4,然后访问节点6,该节点成为3的子节点。]
© www.soinside.com 2019 - 2024. All rights reserved.