Early Riser
생각정리
Early Riser
전체 방문자
오늘
어제
  • 분류 전체보기 (127)
    • JS (19)
    • React (33)
    • Web (2)
    • Library, Framework (14)
    • Algorithm (40)
    • Computer Science (3)
    • 회고 (3)
    • AI (13)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • 글쓰기

공지사항

인기 글

태그

  • 딥러닝
  • 손실함수
  • useEffect
  • lightgbm
  • 구현
  • 밑바닥
  • 비동기
  • boosting
  • 오늘의불경
  • LGBM
  • RNN
  • 백트래킹
  • 부스트캠프 합격
  • 백준
  • 자바스크립트
  • BFS
  • 부스트캠프 9기
  • js
  • react
  • 부스트캠프 합격 후기
  • 완전탐색
  • dfs
  • 파이썬
  • 논문리뷰
  • local minima
  • 프로그래머스
  • global minima
  • javascript
  • 알고리즘
  • useState

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Early Riser

생각정리

백준 2623번: 음악프로그램 (파이썬, 위상정렬, Cycle)
Algorithm

백준 2623번: 음악프로그램 (파이썬, 위상정렬, Cycle)

2022. 8. 28. 13:33

유향그래프를 정렬하는 문제이고 사이클이 없으므로 위상정렬을 이용하여 풀었다.

 

앞서 푼 '2252번: 줄세우기' 문제와 사이클이 존재할 때와 존재 안할 때를 판별하는 것이 차이점이 였다. 위상 정렬을 하기 위해서는 사이클이 없어야 하므로 문제의 조건을 하나 추가한 것 같다.

 

위상정렬은 DFS로 그래프를 정렬 후 뒤짚는 방식으로 구현하였다.

 

사이클 판별은 두가지로 해보았다. 첫번째 방법은 노드  수 N과 크기가 같은 boolean 배열을 하나 만들어서 V의 종단노드부터 boolean 배열의 원소 값을 True로 한다. 그 후 종단노드의 부모노드 순으로 boolean 배열의 원소 값을 True로 한다.

이때 부모노드의 boolean 배열의 원소값이 False라면 Cycle이 존재한다고 판별하는 방법이다. 왜냐하면 cycle이 존재한다면 자식노드와 부모노드가 같기 때문이다. 

코드는 다음과 같다.

import sys


def dfs(n):
    visited[n] = True
    for child in tree[n]:
        if not visited[child]:
            dfs(child)
        elif not finished[child]:  # 부모 노드가 finished[child] = True가 아니다 -> 자식 노드에서 다시 방문하였다 -> cycle 존재
            print(0)
            sys.exit(0)
    rslt.append(n+1)
    finished[n] = True  # 자식 노드부터 finished[n] = True



N, M = map(int, sys.stdin.readline().split())

tree = [[] for _ in range(N)]
visited = [False for __ in range(N)]
finished = [False for ___ in range(N)]
rslt = []

for _ in range(M):
    list_ = list(map(int, sys.stdin.readline().split()))
    for i in range(list_[0]-1):
        tree[list_[i+1]-1].append(list_[i+2]-1)

for j in range(N):
    if not visited[j]:
        dfs(j)

rslt.reverse()

for k in rslt:
    print(k)

   

아래 그림은 간단한 유방향 그래프와 visited, finished배열의 원소들을 나타내 cycle 판별법 이해를 돕기 위해 그려보았다.

유방향 그래프에서 cycle 판별법 도식도 (위: cycle x, 아래: cycle o)

 다음으론 좀 더 직관적인 코드이다.

set을 이용하여 방문한 노드들을 set에 추가하고, 새로운 노드가 이미 방문한 노드들의 집합에 존재할 때 cycle이 존재한다고 판별하는 방법이다. 물론 set 대신 stack을 사용해도 된다.

이 코드로는 처음에 틀렸었는데 그 이유는 dfs가 끝날때 자식노드를 집합에서 제거하지 않았기 때문이다.

왜나하면 부모 노드가 여러 개일수도 있기 때문이고, 그렇다 하더라도 사이클이 존재 하는것은 아닌데 자식 노드가 다시 호출되고 자식노드는 이미 set에 있기 때문에 사이클이 존재한다고 잘못  판별하기 때문이다.

set을 이용해 cycle을 판별한 코드는 다음과 같다.

 

import sys


def dfs(n):
    visited[n] = True
    cycle.add(n)
    for child in tree[n]:
        if child in cycle:
            print(0)
            sys.exit(0)
        if not visited[child]:
            dfs(child)
    rslt.append(n+1)
    cycle.remove(n)  # 자식 노드를 set에서 제거(종단부터)


N, M = map(int, sys.stdin.readline().split())

tree = [[] for _ in range(N)]
visited = [False for __ in range(N)]
rslt = []

for _ in range(M):
    list_ = list(map(int, sys.stdin.readline().split()))
    for i in range(list_[0]-1):
        tree[list_[i+1]-1].append(list_[i+2]-1)

for j in range(N):
    if not visited[j]:
        cycle = set()
        dfs(j)

rslt.reverse()

for k in rslt:
    print(k)

 

set을 이용한 유향 그래프에서 cycle 판별 도식도(위: cycle x, 아래: cycle o)

'Algorithm' 카테고리의 다른 글

백준 17135번: 캐슬 디펜스 (파이썬, 완전탐색, 구현)  (0) 2022.09.07
백준 17070번: 파이프 옮기기 1 (파이썬, DFS, DP)  (2) 2022.09.04
백준 13565번: 침투 (파이썬, DFS)  (0) 2022.08.22
백준 2468번: 안전영역 (파이썬, DFS)  (0) 2022.08.22
백준 2667번: 단지번호 붙이기 (파이썬, BFS)  (0) 2022.08.22
    'Algorithm' 카테고리의 다른 글
    • 백준 17135번: 캐슬 디펜스 (파이썬, 완전탐색, 구현)
    • 백준 17070번: 파이프 옮기기 1 (파이썬, DFS, DP)
    • 백준 13565번: 침투 (파이썬, DFS)
    • 백준 2468번: 안전영역 (파이썬, DFS)
    Early Riser
    Early Riser
    2년차 프론트엔드 개발자입니다. https://github.com/EarlyRiser42

    티스토리툴바