Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

Python으로 그래프 정점 간 도달 가능성 행렬(Reachability Matrix) 계산하기

그래프가 인접 리스트(adjacency list) 형태로 주어졌을 때, 모든 정점 쌍 사이에 경로가 존재하는지를 나타내는 2차원 행렬 M을 구해야 합니다. 행렬의 각 원소는 다음과 같이 정의됩니다.

  • M[i, j] = 1 : 정점 i와 정점 j 사이에 경로가 존재하는 경우
  • M[i, j] = 0 : 경로가 존재하지 않는 경우

예를 들어 아래와 같은 그래프가 입력으로 주어진다고 가정해 보겠습니다.

Python으로 그래프 정점 간 도달 가능성 행렬(Reachability Matrix) 계산하기

이때 기대되는 출력 결과는 다음과 같습니다.

11111
01111
01111
01111
01111

첫 번째 행이 모두 1인 이유는 정점 0에서 시작하면 그래프의 모든 정점에 도달할 수 있기 때문입니다. 반면 정점 0으로 들어오는 간선이 없으므로, 나머지 정점들의 첫 번째 열은 0이 됩니다.

문제 해결 접근 방법

이 문제는 각 정점에서 출발하여 너비 우선 탐색(BFS)을 수행하면 효율적으로 해결할 수 있습니다. 알고리즘의 동작 순서는 다음과 같습니다.

  • n x n 크기의 2차원 행렬 ans를 생성하고(n은 정점의 개수), 모든 값을 0으로 초기화합니다.
  • i를 0부터 n-1까지 반복합니다.
    • 큐 q를 생성하고 i를 삽입합니다.
    • q가 빌 때까지 다음을 반복합니다.
      • q의 맨 앞 요소를 꺼내 node에 저장합니다.
      • ans[i][node]가 이미 1이라면 중복 방문이므로 다음 반복으로 넘어갑니다.
      • ans[i][node]를 1로 설정합니다.
      • node의 이웃 정점들(graph[node])을 모두 q의 뒤에 추가합니다.
  • 모든 반복이 끝나면 ans를 반환합니다.

즉, 각 정점을 시작점으로 삼아 도달할 수 있는 모든 정점을 BFS로 탐색하면서 행렬의 해당 위치를 1로 표시하는 방식입니다. 이미 방문한 노드는 건너뛰므로 불필요한 중복 탐색을 피할 수 있습니다.

구현 예제

class Solution:
    def solve(self, graph):
        ans = [[0 for _ in graph] for _ in graph]
        for i in range(len(graph)):
            q = [i]
            while q:
                node = q.pop(0)
                if ans[i][node]:
                    continue
                ans[i][node] = 1
                neighbors = graph[node]
                for n in neighbors:
                    q.append(n)
        return ans

ob = Solution()
adj_list = [[1, 2], [4], [4], [1, 2], [3]]
print(ob.solve(adj_list))

입력

[[1, 2], [4], [4], [1, 2], [3]]

출력

[[1, 1, 1, 1, 1],
 [0, 1, 1, 1, 1],
 [0, 1, 1, 1, 1],
 [0, 1, 1, 1, 1],
 [0, 1, 1, 1, 1]]

복잡도 분석

각 정점마다 한 번씩 BFS를 수행하므로 전체 시간 복잡도는 O(V × (V + E))입니다. 여기서 V는 정점의 수, E는 간선의 수입니다. 공간 복잡도는 결과 행렬 때문에 O(V²)가 됩니다. 정점 수가 많아지면 플로이드-워셜(Floyd-Warshall) 알고리즘 등 대안적인 방법과 성능을 비교해 보는 것도 좋습니다.