문제

https://www.acmicpc.net/problem/2623


풀이


풀이

  • 34128 KB, 64 ms
from collections import deque
import sys
input = sys.stdin.readline

n, m = map(int, input().split())  # n : 가수의 수, m : 보조 PD의 수

graph = [[] * (n + 1) for _ in range(n + 1)]
indegree = [0] * (n + 1)
q = deque()
ans = []

for _ in range(m) :
    tmp = list(map(int, input().split()))
    x = tmp[0]  # 담당한 가수의 수

    if x <= 1 : continue

    # 선행 관계 넣어주기
    # 보조 출연자 순서 : tmp[1] 부터(포함) x개 -> x-1개까지 쌍
    for i in range(1, x) :
        if tmp[i + 1] not in graph[tmp[i]] :
            graph[tmp[i]].append(tmp[i + 1])
            indegree[tmp[i + 1]] += 1

# 선행 조건 없는거 q에 넣어주기
for i in range(1, n + 1) :
    if indegree[i] == 0 : q.append(i)

# q 빌 때까지 반복문
isCycle = False
while q and not isCycle :
    cur = q.popleft()
    ans.append(cur)

    for nxt in graph[cur] :

        if cur in graph[nxt] : # 사이클 있으면 종료
            isCycle = True
            break

        indegree[nxt] -= 1 # 선행조건 하나 해결

        if indegree[nxt] == 0 : q.append(nxt)

if len(ans) == n :
    for a in ans : print(a)
else : print(0)


풀이 설명

  • 사이클이 있을 수 있는! 위상정렬 문제 -> 사이클 있는지 판단해야 한다
  • 사이클 판단 방법
        if cur in graph[nxt] : # 사이클 있으면 종료
            isCycle = True
            break

: cur이 nxt의 선행 조건인데, nxt도 cur의 선행 조건

그런데.. 사실 이렇게 안해도 된다.

사이클이 있으면 정답 리스트에 1 ~ n이 모두 들어오지 않기 때문!


풀이2

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

n, m = map(int, input().split())
graph = [[] * (n + 1) for _ in range(n + 1)]
indegree = [0] * (n + 1)
ends = set(range(1, n + 1))
q = deque()
ans = []

for _ in range(m) :
    tmp = list(map(int, input().split()))

    l = tmp[0]

    for i in range(1, l) :
        graph[tmp[i]].append(tmp[i + 1]) # 선행관계인 요소 추가
        indegree[tmp[i + 1]] += 1 # 진입차수 ++
        ends.discard(tmp[i + 1])

# 입력 끝

ends = list(ends) # 진입차수 0인 요소만 남음
for e in ends : q.append(e)  # 진입차수 0인 요소 큐에 넣기

while q :
    cur = q.popleft()
    ans.append(cur)

    for nxt in graph[cur] : # 후순이 요소
        indegree[nxt] -= 1 # 선행 요소 하나 완료

        if indegree[nxt] == 0 : q.append(nxt)  # 선행 요소 다 끝나면 큐에 넣기

if len(ans) == n :
    print('\n'.join(map(str, ans)))
else :
    print(0)


배운 점

파이썬

  • 1 ~n 들어있는 set 만들기 : set(range(1, n + 1))
  • set 메소드 remove vs discard : 둘 다 요소를 제거하는 메소드
    • remove는 제거할 요소가 없으면 오류가 발생하지만 discard는 없어도 정상 종료
  • 리스트 요소 한 줄에 하나 씩 출력하기 : print(‘\n’.join(map(str, ans)))


알고리즘 : 위상 정렬

  • 1~n이 unique하게 들어있는 리스트를 만들고, 선행조건 추가될 때 제거하면 for문 이용하지 않고도 진입차수 0인 요소들 찾을 수 있다 !!!


Leave a comment