한 개의 회의실이 있는데 이를 사용하고자 하는 N개의 회의에 대하여 회의실 사용표를 만들려고 한다. 각 회의 I에 대해 시작시간과 끝나는 시간이 주어져 있고, 각 회의가 겹치지 않게 하면서 회의실을 사용할 수 있는 회의의 최대 개수를 찾아보자. 단, 회의는 한번 시작하면 중간에 중단될 수 없으며 한 회의가 끝나는 것과 동시에 다음 회의가 시작될 수 있다. 회의의 시작시간과 끝나는 시간이 같을 수도 있다. 이 경우에는 시작하자마자 끝나는 것으로 생각하면 된다.
첫째 줄에 회의의 수 N(1 ≤ N ≤ 100,000)이 주어진다. 둘째 줄부터 N+1 줄까지 각 회의의 정보가 주어지는데 이것은 공백을 사이에 두고 회의의 시작시간과 끝나는 시간이 주어진다. 시작 시간과 끝나는 시간은 231-1보다 작거나 같은 자연수 또는 0이다.
첫째 줄에 최대 사용할 수 있는 회의의 최대 개수를 출력한다.
무식하게 풀기 - 회의실 사용 가능한 모든 경우의 수 중 가장 많은 경우를 출력한다.
회의 수가 10만이나 입력되기 때문에 아마 모든 경우를 구하기는 메모리제한이 있어서 어려울 것 같다.,
💰 그리디 알고리즘이란?
답을 여러 조각으로 쪼개고, 각 단계마다 지금 당장 가장 좋은 방법만을 선택하는 알고리즘
많은 경우 해를 찾아낼 수 없음, 제한된 경우에서만 사용된다.
그럼에도 그리디 알고리즘을 사용하는 이유?
동적 계획법이나 완전 탐색법보다 훨씬 빠르기 때문에!
속도가 빨라서 그냥 이거 쓸 수 있으면 쓰는게 좋다..
그리디 알고리즘 사용되는 경우
탐욕법을 사용해도 항상 최적해
를 구할 수 있는 문제를 만난 경우
시간이나 공간적 제약으로 인해 최적해를 찾기 너무 어려우면
그냥 대충 탐욕법으로 괜찮은 답을 찾음
탐욕적인 알고리즘이 항상 최적해를 찾아낼 수 있다는 것을 아래 두가지 속성을 증명함으로써 보일 수 있다!
1. 탐욕적 선택 속성
각 단계에서 탐욕적으로 내리는 선택이 항상 최적해로 가는 길 중 하나이며,
탐욕적 선택이 손해가 없다!
를 증명
가장 종료 시간이 빠른 회의를 포함하는 최적해가 반드시 존재한다.
2. 최적 부분 구조
회의실 배정이 가장 많은 경우는 회의시간이 짧은 회의부터 착착 배정하면 가장 많은 회의를 찾을 수 있을 것 같음
제일 가까운 시간
이면서
회의시간
이 짧은
회의
따라서, 가장 가까운 시간
에 시작하는 회의 중 끝나는 시간
이 제일 빠른 회의를 선택!
시간만으로 회의실을 배정하는 경우는 아래처럼 되어 해답을 찾을 수 없다.
✨ 한 회의를 선택할 때마다 겹치는 회의 모두 제거하는 방법
Comparable
을 class에 implememt 한 후, compateTo
메소드를 override
sort내부에서 comparator
를 사용하고, compare
메소드를 override
나는 2번이 편해서 2번을 선택해서 풀이를 진행했다.
정렬 가능한 클래스들의 기본 정렬 기준
과 다르게 정렬하고 싶을 때 사용하는 인터페이스
package: java.util.Comparator
주로 익명 클래스로 사용됨
기본 정렬 방법인 오름차순 정렬을 내림차순으로 정렬할 때 많이 사용
comparator interface를 implements
compare()
메서드 오버라이드 한 myComparator
class 작성
--> 익명 클래스로
도 작성 가능, 아래 코드에서는 익명 클래스로 작성하였음
첫번째 파라미터로 넘어온 객체 < 두번째 파라미터로 넘어온 객체: 음수
리턴
첫번째 파라미터로 넘어온 객체 == 두번째 파라미터로 넘어온 객체: 0
리턴
첫번째 파라미터로 넘어온 객체 > 두번째 파라미터로 넘어온 객체: 양수
리턴
✨ 음수 또는 0이면 객체 자리 유지되며,
양수
인 경우 두 객체의 자리가 변경된다.
Arrays.sort(timetable, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
if (o1[1] == o2[1]) {
return o1[0] - o2[0];
}
return o1[1] - o2[1];
}
});
o1[1]==o2[1] : 두개 끝나는 시간이 같을 경우
return o1[0] - o2[0]
1) o1의 시작하는 시간이 더 빠르면 음수
--> 둘의 위치 바뀌지 않음,
2) o1의 시작하는 시간이 더 크면 양수
--> 둘의 위치 바뀜
--> 더 시작시간이 빠른 게 앞으로 정렬됨
return o1[1] - o2[1]
두개 끝나는 시간 비교해서 o1이 더 빨리 끝날 경우 자리 변경 없고, 더 늦게 끝날 경우 o2와 자리 바뀜
package Greedy;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class BOJ1931 {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int N = s.nextInt();
int[][] timetable = new int[N][2];
for (int i = 0; i < N; i++) {
timetable[i][0] = s.nextInt();
timetable[i][1] = s.nextInt();
}
//timetable 정렬 다시 정의
Arrays.sort(timetable, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
if (o1[1] == o2[1]) {
return o1[0] - o2[0];
}
return o1[1] - o2[1];
}
});
int result = 0;
int end_time = 0;
for (int i = 0; i < N; i++) {
if (timetable[i][0] >= end_time) {
end_time = timetable[i][1];
result++;
}
}
System.out.println(result);
}
}