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

문제를 효율적으로 해결하기 위해 그리디 알고리즘(Greedy Algorithm)과 최소 힙(Min-Heap)을 활용한 접근 방식을 사용하겠습니다. 이 접근 방식은 각 강의를 가능한 한 빨리 끝나는 강의실에 배정하여 전체적으로 필요한 강의실의 수를 최소화하는데 중점을 둡니다.
N개의 강의를 가능한 한 적은 수의 강의실을 사용하여 모두 배정하는 것입니다. 한 강의실에서는 동시에 두 개 이상의 강의를 진행할 수 없으며, 한 강의의 종료 시간과 다른 강의의 시작 시간이 겹치는 것은 허용됩니다.K1 ≤ N ≤ 100,0000 ≤ 시간 ≤ 10^9, 시작 시간 < 종료 시간예제 입력 1:
8
6 15 21
7 20 25
1 3 8
3 2 14
8 6 27
2 7 13
4 12 18
5 6 20
예제 출력 1:
5
4
3
2
4
1
3
4
5
이 문제는 그리디 알고리즘과 최소 힙(Min-Heap)을 활용하여 해결할 수 있습니다. 다음은 그 구체적인 단계입니다:
O(N log N)O(N log N) 시간이 소요됩니다.O(log N) 시간이 소요되므로, 전체적으로 O(N log N) 시간 복잡도를 가집니다.O(N)N개의 강의실을 저장할 수 있으므로, 공간 복잡도는 O(N)입니다.O(N)의 공간을 사용합니다.import sys
import heapq
def assign_lecture_rooms(N, lectures):
# 강의 정렬: 시작 시간 기준, 같을 경우 종료 시간 기준
lectures_sorted = sorted(lectures, key=lambda x: (x[1], x[2]))
# 힙: 현재 사용 중인 강의실의 (종료 시간, 강의실 번호)
min_heap = []
# 사용할 수 있는 강의실 번호의 최소값
available_rooms = []
# 강의실 번호를 저장할 배열 (강의 번호는 1부터 N까지)
room_assignments = [0] * (N + 1)
# 최대 사용된 강의실 번호
max_room = 0
for lecture in lectures_sorted:
lec_num, start, end = lecture
# 힙에서 현재 강의 시작 시간보다 종료 시간이 작거나 같은 강의실을 찾아 재사용
while min_heap and min_heap[0][0] <= start:
ended_time, room_num = heapq.heappop(min_heap)
heapq.heappush(available_rooms, room_num)
if available_rooms:
# 사용할 수 있는 강의실이 있으면 재사용
assigned_room = heapq.heappop(available_rooms)
else:
# 새로운 강의실 할당
max_room += 1
assigned_room = max_room
# 강의에 강의실 할당 기록
room_assignments[lec_num] = assigned_room
# 현재 강의의 종료 시간과 강의실 번호를 힙에 추가
heapq.heappush(min_heap, (end, assigned_room))
return max_room, room_assignments
def main():
import sys
input = sys.stdin.readline
N = int(input())
lectures = []
for _ in range(N):
parts = input().strip().split()
# 강의 번호, 시작 시간, 종료 시간
lec_num, start, end = map(int, parts)
lectures.append((lec_num, start, end))
K, assignments = assign_lecture_rooms(N, lectures)
print(K)
# 강의 번호 순서대로 출력 (1부터 N까지)
for i in range(1, N + 1):
print(assignments[i])
if __name__ == "__main__":
main()
assign_lecture_rooms(N, lectures)N개의 강의를 최소한의 강의실에 배정하고, 각 강의에 배정된 강의실 번호를 반환합니다.N: 강의의 개수lectures: 강의의 정보 리스트. 각 요소는 (강의 번호, 시작 시간, 종료 시간)의 형태입니다.max_room: 필요한 최소 강의실의 개수 Kroom_assignments: 각 강의에 배정된 강의실 번호를 저장한 리스트lectures_sorted: 시작 시간 기준으로 정렬된 강의 리스트min_heap: 현재 사용 중인 강의실의 종료 시간과 강의실 번호를 저장하는 최소 힙available_rooms: 사용할 수 있는(재사용 가능한) 강의실 번호를 저장하는 최소 힙room_assignments: 각 강의에 배정된 강의실 번호를 저장하는 리스트max_room: 현재까지 사용된 최대 강의실 번호lectures_sorted = sorted(lectures, key=lambda x: (x[1], x[2]))
min_heap = []
available_rooms = []
room_assignments = [0] * (N + 1)
max_room = 0
min_heap: 현재 사용 중인 강의실의 종료 시간과 강의실 번호를 저장합니다. (종료 시간, 강의실 번호) 형태로 저장하여, 종료 시간이 가장 빠른 강의실을 힙의 최상단에 유지합니다.available_rooms: 재사용 가능한 강의실 번호를 저장합니다. 새로운 강의실을 할당할 때, 사용 가능한 가장 작은 강의실 번호를 우선적으로 할당합니다.room_assignments: 각 강의에 배정된 강의실 번호를 저장합니다. 강의 번호가 1부터 N까지이므로, 인덱스를 강의 번호로 사용합니다.max_room: 현재까지 사용된 최대 강의실 번호를 추적합니다.for lecture in lectures_sorted:
lec_num, start, end = lecture
# 힙에서 현재 강의 시작 시간보다 종료 시간이 작거나 같은 강의실을 찾아 재사용
while min_heap and min_heap[0][0] <= start:
ended_time, room_num = heapq.heappop(min_heap)
heapq.heappush(available_rooms, room_num)
if available_rooms:
# 사용할 수 있는 강의실이 있으면 재사용
assigned_room = heapq.heappop(available_rooms)
else:
# 새로운 강의실 할당
max_room += 1
assigned_room = max_room
# 강의에 강의실 할당 기록
room_assignments[lec_num] = assigned_room
# 현재 강의의 종료 시간과 강의실 번호를 힙에 추가
heapq.heappush(min_heap, (end, assigned_room))
start보다 종료 시간이 작거나 같은 강의실이 있는지 확인합니다.min_heap의 최상단에 있는 강의실의 종료 시간이 start보다 작거나 같다면, 해당 강의실을 재사용할 수 있습니다.available_rooms 힙에 추가합니다.available_rooms 힙에 재사용 가능한 강의실이 있다면, 가장 작은 강의실 번호를 할당합니다.max_room을 증가시킵니다.room_assignments 리스트에 저장합니다.min_heap에 추가하여, 해당 강의실이 언제 비어나는지를 추적합니다.return max_room, room_assignments
max_room과 각 강의에 배정된 강의실 번호를 반환합니다.def main():
import sys
input = sys.stdin.readline
N = int(input())
lectures = []
for _ in range(N):
parts = input().strip().split()
# 강의 번호, 시작 시간, 종료 시간
lec_num, start, end = map(int, parts)
lectures.append((lec_num, start, end))
K, assignments = assign_lecture_rooms(N, lectures)
print(K)
# 강의 번호 순서대로 출력 (1부터 N까지)
for i in range(1, N + 1):
print(assignments[i])
if __name__ == "__main__":
main()
N을 입력받습니다.N개의 줄에서 각 강의의 정보를 입력받아 lectures 리스트에 저장합니다.assign_lecture_rooms 함수를 호출하여, 필요한 최소 강의실의 개수 K와 각 강의에 배정된 강의실 번호 assignments를 얻습니다.K를 출력합니다.N개의 줄에 걸쳐 각 강의 번호 순서대로 배정된 강의실 번호를 출력합니다.8
6 15 21
7 20 25
1 3 8
3 2 14
8 6 27
2 7 13
4 12 18
5 6 20
강의 정보:
정렬된 강의 순서:
강의 배정 과정:
min_heap 비어 있음 → 새로운 강의실 1 할당min_heap: [(14, 1)]room_assignments[3] = 1max_room = 1min_heap 최상단 (14,1) > 3 → 새로운 강의실 2 할당min_heap: [(8, 2), (14, 1)]room_assignments[1] = 2max_room = 2min_heap 최상단 (8,2) > 6 → 새로운 강의실 3 할당min_heap: [(8, 2), (14, 1), (27, 3)]room_assignments[8] = 3max_room = 3min_heap 최상단 (8,2) > 6 → 새로운 강의실 4 할당min_heap: [(6,4), (8,2), (27,3), (20,5)] (히프의 구조는 다를 수 있지만, 개념적으로 이해)room_assignments[5] = 4max_room = 4min_heap 최상단 (8,2) > 7 → 새로운 강의실 5 할당min_heap: [(7,5), (8,2), (27,3), (20,5), (13,2)]room_assignments[2] = 5max_room = 5min_heap 최상단 (13,2) <= 12 → 해당 강의실 재사용 → 강의실 2min_heap: [(13,2), (14,1), (27,3), (20,5), (18,2)]room_assignments[4] = 2min_heap 최상단 (18,2) <= 15 → 해당 강의실 재사용 → 강의실 2min_heap: [(18,2), (14,1), (27,3), (20,5), (21,2)]room_assignments[6] = 2min_heap 최상단 (18,2) <= 20 → 해당 강의실 재사용 → 강의실 2min_heap: [(20,2), (14,1), (27,3), (21,2), (25,2)]room_assignments[7] = 2최종 배정:
K = 5출력:
5
4
3
2
4
1
3
4
5
Note: 위의 배정 과정은 힙의 내부 구조에 따라 실제 할당된 강의실 번호와 다를 수 있습니다. 중요한 것은 최종적으로 최소 강의실 수 K와 각 강의에 배정된 강의실 번호가 올바르게 출력된다는 점입니다.
sorted(lectures, key=lambda x: (x[1], x[2]))O(N log N)O(N log N) 시간 복잡도를 가집니다.for lecture in lectures_sorted:O(log N) (힙에서 요소를 삽입/삭제하는 데 소요되는 시간)O(log N)O(N log N)O(N log N) 시간 복잡도를 가집니다.available_rooms 힙은 강의실 번호를 효율적으로 재사용하기 위해 사용됩니다.O(log K) 시간이 소요되며, K는 사용 중인 강의실의 수입니다. 하지만 K ≤ N이므로, O(log N)으로 근사할 수 있습니다.총 시간 복잡도: O(N log N) + O(N log N) = O(N log N)
lectures_sorted: O(N)min_heap: O(K) (최대 N 강의실)available_rooms: O(K) (최대 N 강의실)K는 필요한 최소 강의실 수로, 최악의 경우 K = Nroom_assignments: O(N)총 공간 복잡도: O(N) + O(K) + O(N) = O(N)
heapq 모듈을 사용하여 최소 힙을 구현합니다.(종료 시간, 강의실 번호) 튜플을 저장하여, 종료 시간이 가장 빠른 강의실이 힙의 최상단에 위치하도록 합니다.available_rooms)heapq 모듈을 사용하여 최소 힙을 구현합니다.room_assignments)i에 강의 번호 i에 배정된 강의실 번호를 저장합니다.