BOJ #1931 회의실 배정
문제
한 개의 회의실이 있는데 이를 사용하고자 하는 N개의 회의에 대하여 회의실 사용표를 만들려고 한다. 각 회의 I에 대해 시작시간과 끝나는 시간이 주어져 있고, 각 회의가 겹치지 않게 하면서 회의실을 사용할 수 있는 회의의 최대 개수를 찾아보자. 단, 회의는 한번 시작하면 중간에 중단될 수 없으며 한 회의가 끝나는 것과 동시에 다음 회의가 시작될 수 있다. 회의의 시작시간과 끝나는 시간이 같을 수도 있다. 이 경우에는 시작하자마자 끝나는 것으로 생각하면 된다.
입력
첫째 줄에 회의의 수 N(1 ≤ N ≤ 100,000)이 주어진다. 둘째 줄부터 N+1 줄까지 각 회의의 정보가 주어지는데 이것은 공백을 사이에 두고 회의의 시작시간과 끝나는 시간이 주어진다. 시작 시간과 끝나는 시간은 231-1보다 작거나 같은 자연수 또는 0이다.
출력
첫째 줄에 최대 사용할 수 있는 회의의 최대 개수를 출력한다.
소스코드(C언어)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int N, start[100000], end[100000];
void swap(int i, int j) {
int tmp = start[i];
start[i] = start[j];
start[j] = tmp;
tmp = end[i];
end[i] = end[j];
end[j] = tmp;
}
void heapify(int i, int n) { //i번째에서 heapify, 최대 인덱스는 n
int left = 2 * i + 1;
int right = 2 * i + 2;
int max = i;
if (left <= n) { //i가 left node가 아닐 때
if (end[left] > end[max])
max = left;
else if (end[left] == end[max] && start[left] > start[max])
max = left;
if (right <= n) {
if (end[right] > end[max])
max = right;
else if (end[right] == end[max] && start[right] > start[max])
max = right;
}
if (max != i) {
swap(max, i);
heapify(max, n);
}
}
}
int main() {
scanf("%d", &N);
for (int i = 0; i < N; i++) {
scanf("%d %d", &start[i], &end[i]);
}
//end를 기준으로 sorting
for (int i = (N / 2) - 1; i >= 0; i--) { //build max heap
heapify(i, N - 1);
}
for (int i = 0; i < N; i++) {
swap(0, N - 1 - i);
heapify(0, N - 2 - i);
}
int num = 1, time = end[0];
for (int i = 1; i < N; i++) {
if (start[i] >= time) {
num++;
time = end[i];
}
}
printf("%d\n", num);
return 0;
}
Idea
그리디 알고리즘을 사용한다.
즉, 현재 시간을 기준으로 가장 빨리 끝나는 것을 고르는 것이다.
남은 시간이 길수록 더 많은 공연을 할 수 있기 때문이다.
따라서 힙 정렬을 사용하여 끝나는 시간이 가장 느린 것을 기준으로 정렬한다.
만일 끝나는 시간이 같다면, 시작 시간이 빠른 것 순으로 정렬한다.
위 코드는 6개월 전에 짠 코드인데,
이를 통해 힙을 만드는 방법이 2가지가 있음을 알 수 있다.
하나는 모든 노드에 대해서 부모 노드와 비교하며 힙을 만드는 방법이고,
또 다른 하나는 리프 노드를 제외한 모든 노드에 대하여 자식 노드들과 비교하는 방법이다.
음.. 근데 두가지 모두 시간복잡도가 O(n*logn)으로 동일하다.