위상정렬(Topological Sort)

이영구·2022년 9월 9일
0

Algorithm

목록 보기
12/19
  • DAG(Directed Acyclic Graph)
    : 사이클이 없는 방향 있는 그래프

  • 위상 정렬(Topological Sort)
    : 그래프의 간선 u → v에서 v를 선행하기에 앞서 u를 먼저 수행해야 한다는 의미에서 봤을 때 정점의 순서를 찾아주는 알고리즘
    : 보통 위상정렬의 결과는 여러가지가 있다. (DOF == 0을 만족하는 node간에는 우선 순위가 없기 때문)

  • 방법론
    : 구현에는 BFS를 이용하는 방법과 DFS를 이용하는 방법이 있다.
    : in-degree가 0인 node를 해당 순서(보통은 queue)에 추가하면서 해결
    : 인접행렬의 경우는 간선을 지우는 것은 해당 행열의 값을 0으로 바꾸면 쉬운 일이지만, 인접리스트에서는 해줘야 할 일이 많고 복잡하다. 따라서, 실제로 인접리스트의 간선을 지우지 않고, in-degree만 관리하면 된다.
    : 사이클이 있는 그래프에서는 처음 지점을 뽑을 수 없기 때문에 수행이 불가능하다.

  • BFS 방법 구현
    : BFS와 유사하게 구현할 수 있다. 다만, BFS에서는 방문하지 않은 노드를 queue에 추가하면서 진행해 나가는 반면, 방문하지 않는 점과 동시에 in-degree가 0이 되었는지를 추가해야 한다.
    : BFS의 시간 복잡도인 O(V+E)인데 V는 queue에 들어왔다 나갔다하는 방법 간선(E)는 한번씩 순회하기 때문에 O(E)와 같다.

  • DFS 방법 구현
    : DFS에서는 그래프의 간선을 모두 뒤집어 놓고 DFS를 수행하고, 정점이 스택에서 빠져나오는 순서를 기록하면 위상 정렬의 순서와 같아지게 된다.

백준 1948 문제

import sys
from collections import deque
rdln = sys.stdin.readline

n = int(rdln())
m = int(rdln())

ind = [0] * (n+1) # in-degree1
ind2 = [0] * (n+1) # in-degree2
d = [0] * (n+1)
check = [False] * (n+1) # 방문했는지 확인하는 배열
graph = [[] for _ in range(1, n+1)] # graph1
graph2 = [[] for _ in range(1, n+1)] # graph2
for _ in range(m):
    st, en, co = map(int, rdln().split())
    graph[st].append((en, co))
    graph2[en].append((st, co))
    ind[en] += 1
    ind2[st] += 1

start, end = map(int, rdln().split())
queue = deque()
for i in range(1, n+1):
    if ind[i] == 0:
        queue.append(i)

while queue:
    x = queue.popleft()
    for _en, _co in graph[x]:
        d[_en] = max(d[_en], d[x] + _co) # 최대 distance구하기
        ind[_en] -= 1 # _en node 1 degree 줄이기
        if ind[_en] == 0:
            queue.append(_en)

sys.stdout.write(f"{d[end]}\n")

ans = 0
check[end] = True
for i in range(1, n+1):
    if ind2[i] == 0:
        queue.append(i)

while queue:
    x = queue.popleft()
    for _st, _co in graph2[x]:
        if check[x] and (d[x] - d[_st] == _co): # x 노드에서 _st 비용 차이가 _co면 해당 노드 check[_st] = True
            check[_st] = True 
            ans += 1
        ind2[_st] -= 1
        if ind2[_st] == 0:
            queue.append(_st)

sys.stdout.write(f"{ans}\n") 
profile
In to the code!

0개의 댓글