본문 바로가기

[이것이 코딩 테스트다] with Python

[이것이 코딩 테스트다] 커리큘럼 with Python

🔒 문제


 철수는 온라인으로 컴퓨터공학강의를 듣고 있다. 이때 각 온라인강의는 선수강의가 있을 수 있는데, 선수 강의가 있는 강의는 선수 강의를 먼저. 들어야만 해당강의를 들을 수 있다. 예를들어 '알고리즘’ 강의의 선수 강의로 '자료구조'가 존재한다면, ‘자료구조를 들은 이후에 ‘알고리즘' 강의를 들을 수 있다.
철수는 총 N개의 강의를 듣고자 한다. 모든 강의는 1번부터 N번까지의 번호를 가진다. 또한 동시에 여러 개의 강의를 들을 수 있다고 가정한다. 
 철수가 듣고자 하는 N개의 강의 정보가 주어졌을 때, N개의 강의에 대하여 수강하기까지 걸리는 최소 시간을 각각 출력하는 프로그램을 작성하시오.

입력


첫째줄에 철수가 듣고자 하는 강의의 수 N(1≤N≤500)이 주어진다.
다음 N개의 줄에는 각 강의의 강의 시간과 그 강의를 듣기 위해 먼저 들어야하는 강의들의 번호가 자연수로 주어지며, 각. 이때 강의시간은 100,000이하의 자연수이다 .각 강의번호는 1부터 N까지로 구성되며. 각줄은 -1로 끝난다.

5
10 -1
10 1 -1
4 1 -1
4 3 1 -1
3 3 -1

출력


10
20
14
18
17

✅ 해설

  • 과목 시간과 선수 과목 입력받기
    • 수강 시간은 따로 수강 시간 테이블에 저장
    • 한 줄에 수강 시간과 -1을 제외하고 숫자가 몇 번 입력되는지 세서 진입 차수에 저장
    • 새로운 배열에 선수 과목 저장
# 과목 시간과 선수 과목 입력받기
for subject in range(1, n+1):
    data = list(map(int, input().split()))
    # 수강 시간 저장
    time[subject] = data[0]
    for i in data[1:-1]:
        # 진입 차수 저장
        indegree[subject] += 1
        # 선수 과목 저장
        graph[i].append(subject)
  • 위상 정렬
    • 진입 차수가 0인 노드를 큐에 삽입
    • 큐에서 현재 노드를 가져와 연관된 노드와의 간선을 끊고 진입 차수를 줄임
    • 먄약 연결된 노드가 새롭게 진입 차수가 0이 된다면 큐에 삽입
    • 위 과정을 큐가 빌 때까지 반복
    • 위상 정렬에 대한 더 자세한 내용은 https://evolving-developer-new.tistory.com/60 참고
  • 앞선 선수 과목을 모두 들어야만 다음 과목을 들을 수 있으며, 여러 과목을 동시에 들을 수 있다는 뜻은 그래프 경로 중에서 더 큰 값을 선택하는 것과 같다.
    • 만약 과목 a의 선수 과목 b, c가 존재하고, b, c의 수강시간이 각 10시간, 20시간일 때,
    • max(b 시간, c 시간) = 20. 최소 20시간 후에 과목 a를 수강할 수 있기 때문이다.

💻 코드

# 강의 n개 입력받기
import copy

n = int(input())

# 진입차수를 저장하는 배열
indegree = [0] * (n+1)

#  수강 시간을 저장하는 배열
time = [0] * (n+1)

# 커리큘럼의 관계를 그래프 형태로 저장
graph = [[] for _ in range(n+1)]

# 과목 시간과 선수 과목 입력받기
for subject in range(1, n+1):
    data = list(map(int, input().split()))
    # 수강 시간 저장
    time[subject] = data[0]
    for i in data[1:-1]:
        # 진입 차수 저장
        indegree[subject] += 1
        # 선수 과목 저장
        graph[i].append(subject)

# 위상 정렬
def topological():
    # 결과
    result = copy.deepcopy(time)
    queue = []
    # 진입차수가 0이면 큐에 삽입
    for i in range(1, n+1):
        if indegree[i] == 0:
            queue.append(i)

    # 큐가 빌 때까지 반복
    while queue:
        now = queue.pop()
        for node in graph[now]:
            # 더 큰 값을 선택해야 모든 선수과목을 수강하고 다음 과목 수강 가능
            result[node] = max(result[node], result[now] + time[node])
            # 진입차수 1 줄이기
            indegree[node] -= 1
            # 만약 진입차수가 0이면 큐에 삽입
            if indegree[node] == 0:
                queue.append(node)
    print(result)

topological()