문제
철수는 온라인으로 컴퓨터공학강의를 듣고 있다.
이때 각 온라인강의는 선수강의가 있을 수 있는데, 선수 강의가 있는 강의는 선수 강의를 먼저 들어야만 해당강의를 들을 수 있다.
예를들어 '알고리즘’ 강의의 선수 강의로 '자료구조'가 존재한다면, ‘자료구조를 들은 이후에 ‘알고리즘' 강의를 들을 수 있다.
철수는 총 N개의 강의를 듣고자 한다. 모든 강의는 1번부터 N번까지의 번호를 가진다.
또한 동시에 여러 개의 강의를 들을 수 있다고 가정한다.
예를 들어 N=3일 때, 3번강의의 선수 강의로 1번과 2번강의가 있고, 1번과 2번강의는 선수강의가 없다고 가정하자.
그리고 각 강의에 대하여 강의 시간이 다음과 같다고 가정하자.
1번 강의: 30시간
2번 강의: 20시간
3번 강의: 40시간
이 경우 1번 강의를 수강하기까지의 최소 시간은 30시간, 2번 강의를 수강하기까지의 최소 시간은 20시간, 3번 강의를 수강하기까지의 최소 시간은 70시간이다.
철수가 듣고자 하는 N개의 강의 정보가 주어졌을 때, N개의 강의에 대하여 수강하기까지 걸리는 최소 시간을 각각 출력하는 프로그램을 작성하시오.
입력 조건
첫째줄에 철수가 듣고자 하는 강의의 수 N(1≤N≤500)이 주어진다.
다음 N개의 줄에는 각 강의의 강의 시간과 그. 강의를 듣기 위해 먼저 들어야하는 강의들의 번호가 자연수로 주어지며, 각. 자연수는 공백으로 구분한다. 이때 강의시간은 100,000이하의 자연수이다 .각 강의번호는 1부터 N까지로 구성되며. 각줄은 -1로 끝난다.
출력 조건
N개의 강의에 대하여 수강하기까지 걸리는 최소 시간을 한 줄에 하나씩 출력한다.
문제 해설
이 문제는 위상 정렬(Topological Sort) 알고리즘을 활용하여 풀 수 있습니다.
문제에서 각 강의가 선수 강의를 가질 수 있고, 선수 강의를 듣기 전에 해당 강의를 듣지 못한다는 조건이 있습니다.
이런 선후 관계가 있는 강의들을 그래프로 표현할 수 있습니다.
그래프에서 선후관계를 지키면서 모든 강의를 수강하기 위해선 어떤 강의를 먼저 들어야 하는지 찾아야 합니다.
여기서 사용되는 알고리즘이 바로 위상 정렬입니다.
위상정렬은 그래프의 노드들을 선형적으로 나열하는 알고리즘으로, 그래프에서 선후 관계가 있는 노드를 순서대로 나열하는 것이 목표합니다.
따라서 위상 정렬을 사용하면 선수 강의를 먼저 듣고, 그 다음에 들어야 하는 강의들을 찾아서 최소 시간을 계산할 수 있습니다.
아래는 문제를 푸는 단계별 설명입니다.
1. 먼저, 입력을 받고 각 강의에 대한 정보를 그래프로 표현합니다. 각 노드는 강의를 나타내고, 간선은 선수 강의를 나타냅니다.
각 노드의 진입 차수(선수 강의의 개수)를 기록합니다.
2. 위상 정렬 알고리즘을 사용하여 그래프에서 진입 차수가 0인 노드(선수 강의가 없는 강의)를 찾아 큐에 넣습니다.
3. 큐에서 노드를 하나씩 꺼내며 해당 노드를 듣기 위한 최소 시간을 갱신합니다. 이때, 각 노드의 선수 강의를 듣기 위한 최소 시간을 고려하여 갱신합니다.
4. 모든 노드를 방문하고 나면, 각 강의를 듣기까지 걸리는 최소 시간이 계산됩니다.
소스 코드
from collections import deque
# 입력 받기
n = int(input()) # 강의 수 N을 입력 받음
graph = [[] for _ in range(n + 1)] # 그래프 초기화
in_degree = [0] * (n + 1) # 진입 차수(선수 강의 수) 초기화
time = [0] * (n + 1) # 각 강의의 시간 초기화
for i in range(1, n + 1):
data = list(map(int, input().split())) # 각 강의의 정보를 입력 받음
time[i] = data[0] # 각 강의의 시간을 저장
for x in data[1:-1]: # 선수 강의들을 확인하고 그래프와 진입 차수를 업데이트
in_degree[i] += 1
graph[x].append(i) # 선수 강의에서 현재 강의로의 간선 추가
# 위상 정렬 함수
def topological_sort():
result = time[:] # 각 강의의 최소 시간을 저장할 리스트 초기화
q = deque() # 큐를 생성하여 위상 정렬 진행
for i in range(1, n + 1):
if in_degree[i] == 0: # 진입 차수가 0인 (선수 강의가 없는) 강의를 큐에 추가
q.append(i)
while q:
now = q.popleft() # 큐에서 현재 강의를 꺼냄
for next_node in graph[now]: # 현재 강의의 선후 관계에 있는 다음 강의들에 대해서
result[next_node] = max(result[next_node], result[now] + time[next_node])
# 최소 시간을 업데이트 (현재 강의를 듣는데 걸리는 시간과 다음 강의를 듣는데 걸리는 시간 중 더 오래 걸리는 것 선택)
in_degree[next_node] -= 1 # 진입 차수 감소
if in_degree[next_node] == 0: # 진입 차수가 0이 되면 큐에 추가
q.append(next_node)
for i in range(1, n + 1):
print(result[i]) # 각 강의의 최소 시간 출력
# 위상 정렬 수행
topological_sort()
위 코드는 각 강의의 선후 관계를 고려하여 최소 시간을 계산하고 출력하는 코드입니다. 입력 조건에 따라 그래프를 구성하고, 위상 정렬을 수행하여 각 강의의 최소 시간을 계산합니다. 이렇게 구현한 코드를 실행하면 각 강의를 듣기까지 걸리는 최소 시간이 출력됩니다.
입력 예시
5
10 -1
10 1 -1
4 1 -1
4 3 1 -1
3 3 -1
첫 번째 줄에
(10 -1) 은 강의 1의 강의 시간이 10시간이며, 선후 강의가 없다는 것을 의미합니다.
따라서 강의 1은 선후 관계에 있는 다른 강의를 듣기 전에 들을 수 있는 독립적인 강의라고 할 수 있습니다.
그 다음 두 번째 줄은 강의 2에 해당합니다.
(10 1 -1) 은 강의 2를 들을려면 먼저 강의 1을 들어야한 다는 것을 의미합니다. (선수 강의로 강의 1이 필요하다는 뜻)
전체 그래프를 시각화하면 다음과 같습니다.
출력 예시
5
10 -1
10 1 -1
4 1 -1
4 3 1 -1
3 3 -1
10
20
14
18
17
'개발 > CodingTest' 카테고리의 다른 글
[백준] 11399번 - ATM - 그리드 알고리즘 (1) | 2024.01.22 |
---|---|
[백준] 1931번 - 회의실 배정 - 그리디 알고리즘 (1) | 2024.01.22 |
[이코테] 도시 분할 계획 - 이해까지 도와주는 풀이 (1) | 2024.01.21 |
[이코테] 팀 결성 - 이해까지 도와주는 풀이 (0) | 2024.01.21 |
[자료구조] 진입차수란? (1) | 2024.01.21 |