[파이썬] 그래프의 이중 연결 요소와 절단점 찾기

그래프는 수많은 연결된 노드들의 집합으로 이루어진 자료구조입니다. 그래프를 통해 다양한 문제를 해결할 수 있습니다. 이중 연결 요소와 절단점은 그래프에서 중요한 개념 중 하나로, 그래프의 구조를 파악하는 데 도움이 됩니다. 이번 포스트에서는 Python을 이용하여 그래프의 이중 연결 요소와 절단점을 찾는 방법에 대해 알아보겠습니다.

이중 연결 요소 (Biconnected Component) 찾기

이중 연결 요소는 그래프에서 어떤 에지를 삭제해도 그래프가 여전히 연결되어있는 부분 그래프입니다. 이중 연결 요소를 찾는 알고리즘 중 하나로는 Tarjan’s algorithm이 널리 알려져 있습니다. 이 알고리즘은 DFS (Depth-First Search)를 기반으로 하며, 각 노드에 대해 DFS를 수행하면서 이중 연결 요소를 찾아냅니다.

아래는 이중 연결 요소를 찾는 Python 코드의 예시입니다.

def find_biconnected_components(graph):
    low = []
    disc = []
    parent = []
    visited = []
    time = 0
    biconnected_components = []

    def dfs(node):
        nonlocal time

        disc[node] = time
        low[node] = time
        time += 1
        visited[node] = True
        children = 0

        for neighbor in graph[node]:
            if not visited[neighbor]:
                children += 1
                parent[neighbor] = node
                dfs(neighbor)

                low[node] = min(low[node], low[neighbor])

                if (parent[node] == -1 and children > 1) or (parent[node] != -1 and low[neighbor] >= disc[node]):
                    biconnected_components.append((node, neighbor))

            elif neighbor != parent[node]:
                low[node] = min(low[node], disc[neighbor])

    for i in range(len(graph)):
        low.append(float('inf'))
        disc.append(float('inf'))
        parent.append(-1)
        visited.append(False)

    for i in range(len(graph)):
        if not visited[i]:
            dfs(i)

    return biconnected_components

위의 코드는 그래프를 인접 리스트로 표현한 graph와 함께 사용될 수 있습니다. find_biconnected_components 함수를 호출하면 그래프의 모든 이중 연결 요소를 찾아서 반환합니다.

절단점 (Cut Vertex) 찾기

절단점은 그래프에서 한 노드를 삭제했을 때 그래프가 두 개 이상의 컴포넌트로 분리되는 노드입니다. 절단점은 그래프의 중요한 구조를 파악하는 데 도움이 됩니다. 절단점을 찾는 알고리즘 중 하나로는 Tarjan’s algorithm이 있습니다. 이 알고리즘은 DFS를 기반으로 하며, 각 노드에 대해 DFS를 수행하면서 절단점을 찾아냅니다.

아래는 절단점을 찾는 Python 코드의 예시입니다.

def find_cut_vertices(graph):
    low = []
    disc = []
    parent = []
    visited = []
    is_cut_vertex = []
    time = 0
    cut_vertices = []

    def dfs(node):
        nonlocal time

        disc[node] = time
        low[node] = time
        time += 1
        visited[node] = True
        children = 0

        for neighbor in graph[node]:
            if not visited[neighbor]:
                children += 1
                parent[neighbor] = node
                dfs(neighbor)

                low[node] = min(low[node], low[neighbor])

                if parent[node] == -1 and children > 1:
                    is_cut_vertex[node] = True

                if parent[node] != -1 and low[neighbor] >= disc[node]:
                    is_cut_vertex[node] = True

            elif neighbor != parent[node]:
                low[node] = min(low[node], disc[neighbor])

    for i in range(len(graph)):
        low.append(float('inf'))
        disc.append(float('inf'))
        parent.append(-1)
        visited.append(False)
        is_cut_vertex.append(False)

    for i in range(len(graph)):
        if not visited[i]:
            dfs(i)

    for i in range(len(graph)):
        if is_cut_vertex[i]:
            cut_vertices.append(i)

    return cut_vertices

위의 코드도 그래프를 인접 리스트로 표현한 graph와 함께 사용될 수 있습니다. find_cut_vertices 함수를 호출하면 그래프의 모든 절단점을 찾아서 반환합니다.

마치며

이중 연결 요소와 절단점은 그래프의 구조를 파악하는 데 중요한 개념입니다. Python을 이용하여 그래프의 이중 연결 요소와 절단점을 찾는 방법에 대해 살펴보았습니다. 이 알고리즘들은 다양한 그래프 기반 문제를 해결하는 데 도움이 될 수 있습니다.