아이디어
- 완전탐색 불가능
- 그리디 불가능
- DP를 시도할 수 있나? 가능할 것 같다.
- '회의실 배정' 문제와 같이 종료 시각 순으로 정렬한 뒤, 가능한 모든 종료 시각에 대해 DP를 돌릴 수도 있겠다. 아래와 같은 형태가 되었을 것
memo[i] = Math.max(memo[meeting[i].start], memo[i-1];
- 그러나 시각의 범위가 231−1까지므로 메모리 초과가 날 것이다.
- 여태까지 고려한 회의의 개수에 대해 DP를 진행하면 되겠다. 그러나 이 경우 식이 좀 복잡하다.
memo[i] = Math.max(
memo[(meeting[i].start 안에 끝나는 회의 중 가장 큰 index)],
memo[i-1]
);
- 위 식에서 말하는 index는 이진 탐색으로 찾으면 되겠다. 회의를 정렬했으므로.
코드
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
static BufferedReader rd = new BufferedReader(new InputStreamReader(System.in));
static StringBuilder sb = new StringBuilder();
static StringTokenizer tk = null;
static class Meeting implements Comparable<Meeting> {
int start, end, people;
public Meeting(int start, int end, int people) {
super();
this.start = start;
this.end = end;
this.people = people;
}
@Override
public int compareTo(Meeting o) {
return Integer.compare(this.end, o.end);
}
}
static int N;
static Meeting[] meetings;
static int[] memo;
public static void main(String[] args) throws Exception {
N = Integer.parseInt(rd.readLine());
meetings = new Meeting[N+1];
memo = new int[N+1];
meetings[0] = new Meeting(0, 0, 0);
for (int i=1; i<=N; i++) {
tk = new StringTokenizer(rd.readLine());
int start = Integer.parseInt(tk.nextToken());
int end = Integer.parseInt(tk.nextToken());
int people = Integer.parseInt(tk.nextToken());
meetings[i] = new Meeting(start, end, people);
}
Arrays.sort(meetings);
memo[0] = 0;
for (int i=1; i<=N; i++) {
int lo = 0;
int hi = N;
int mid;
while (lo <= hi) {
mid = (lo + hi) / 2;
if (meetings[mid].end > meetings[i].start)
hi = mid - 1;
else
lo = mid + 1;
}
memo[i] = Math.max(memo[hi] + meetings[i].people, memo[i-1]);
}
System.out.println(memo[N]);
}
}
메모리 및 시간
리뷰
- Java의
Arrays.binarySort()
메소드를 이용할 수 없는 형태라 직접 구현해야 했다.
- 이 풀이를 떠올린 것이 자랑스럽다!
new Meeting(-1, meetings[i].start, -1)
가상의 회의를 만들어 Arrays.binarySearch()
를 쓸 수도 있을 것 같다.