코딩가딩가

[JAVA]BOJ 1931, 회의실 배정

Noooodle 2024. 7. 28. 15:39

정렬과 그리디 알고리즘을 사용한 문제이다. 그리디 알고리즘은 매 단계마다 최선의 선택을 하는 방법을 말한다. 난 처음에 그리디 알고리즘 문제인지 모르고 모든 가지수를 다 선택하는 방식을 재귀로 짰더니 시간초과가 났다. 그리디 알고리즘인 걸 알고 고쳤더니 통과했다!

 

1. 끝나는 시간을 기준으로 정렬을 한다.

1-2. 만약 끝나는 시간이 같다면, 시작 시간이 빠른 것이 먼저 온다.

2. 첫 번째 회의를 선택하고, 그 다음으로 선택 가능한 회의를 선택한다.

3. 2번을 계속 반복해서 모든 회의를 다 살펴본다.

 

단순하다.. 이렇게 적으니까.. 그리디 알고리즘이라서 가능한거다.

 

1. 1-2. 정렬하기

사용자 정의 클래스를 하나 만든다. 나는 Meeting이라고 만들었다. Meeting 클래스는 start(시작시간), end(끝나는시간), term(회의시간 = 끝나는시간 - 시작시간) 세 개의 필드를 가진다.

그리고 Meeting을 정렬할 것이므로 정렬방법을 오버라이딩해준다. 

public class Meeting implements Comparable<Meeting>{
    private int start;
    private int end;
    private int term;

    // 생성자 생략

    @Override
    public int compareTo(Meeting o) {
        if(end == o.end) // 끝나는 시간이 같으면
            return start - o.start;
        return end - o.end;
    }

    // getter 생략
}

 

2. 3. 회의 선택하기

회의를 선택하는 방법은, 다음에 선택할 회의의 끝나는 시간(end)과, 이전에 선택된 회의의 끝나는 시간(end), 그리고 다음에 선택할 회의시간(term)을 비교하는 것이다. 예를 들면

 

순서대로 start, end, term이다.

    1 5 4 --> 선택
    4 6 2 --> 6(선택할 회의의 end) - 5(이전에 선택된 회의의 end) = 1 이고 term은 2, 2 <= 1 을 만족하지 않으므로 선택하지 않음 
    5 10 5 --> 10 - 5 = 5, term은 5, 5 <= 5 을 만족하므로 선택
    답 : 2

 

이런 방식으로 최적의 선택을 하고, 끝까지 모든 회의를 봤을때, 선택된 회의의 개수가 최선의 경우이다.

 

이 문제의 또 다른 함정은 (2, 2) (2, 2) (2, 2) 인 경우에 다 같은 회의니까 1이 나와야 할 것 같지만 답은 3이라는 것이다.. 질문계시판에 반례가 많이 있고 다 확인해보면 된다. 근데 위 알고리즘으로 풀면 사실 다 적용되긴한다.

i = 0; // i는 이전에 선택된 회의의 인덱스
for(j=1;j<N;j++){
    if(meetings[j].getTerm() <= (meetings[j].getEnd() - meetings[i].getEnd())) {
        cnt++;
        i = j; // 회의를 선택했으므로 i를 바꿔줌
    }
}

아래는 전체 코드이다.

public class Meeting implements Comparable<Meeting>{
    private int start;
    private int end;
    private int term;

    public Meeting() {
    }

    public Meeting(int start, int end, int term) {
        this.start = start;
        this.end = end;
        this.term = term;
    }

    @Override
    public int compareTo(Meeting o) {
        if(end == o.end) // 끝나는 시간이 같으면
            return start - o.start;
        return end - o.end;
    }

    public int getStart() {
        return start;
    }

    public int getEnd() {
        return end;
    }

    public int getTerm() {
        return term;
    }
}
import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;

public class BOJ1931 {
    public static void main(String[] args) throws IOException {
        // 사용자 정의 클래스 하나 만들고, start, end, term(차이) 필드 3개 주기
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        int N, i, j, start, end, cnt = 1;
        String str;
        StringTokenizer st;

        N = Integer.parseInt(br.readLine());
        Meeting[] meetings = new Meeting[N];

        // 입력
        for(i=0;i<N;i++){
            str = br.readLine();
            st = new StringTokenizer(str);

            start = Integer.parseInt(st.nextToken());
            end = Integer.parseInt(st.nextToken());
            meetings[i] = new Meeting(start, end, end - start);
        }

        // end를 기준으로 정렬
        Arrays.sort(meetings);

        // 그리디 알고리즘으로 풀기!!
        // meetings[0]은 이미 선택함 -> [1]부터 확인하기
        i = 0;
        for(j=1;j<N;j++){
            if(meetings[j].getTerm() <= (meetings[j].getEnd() - meetings[i].getEnd())) {
                cnt++;
                i = j;
            }
        }

        System.out.println(cnt);
    }
}

반례들 예시

 

    [0] 1 4 = 3 
    [1] 3 5 = 2 > 1
    [2] 0 6 = 6 > 2
    [3] 5 7 = 2 <= 3(7 - 4) 보다 작거나같음
    [4] 3 8 = 5 > 1
    [5] 5 9 = 4 > 2
    [6] 6 10 = 4 > 3
    [7] 8 11 = 3 <= 3 보다 작거나같음
    [8] 8 12 = 4 > 1
    [9] 2 13 = 11 > 2
    [10] 12 14 = 2 <= 3 보다 작거나같음



    1 2 = 1
    2 2 = 0 <= 2 - 2
    답 : 2

    1 1 = 0
    1 2 = 0 <= 2 - 2
    답 : 2

    2 2 = 0
    2 2 = 0
    2 2 = 0
    답 : 3

    1 5
    4 6
    5 10
    답 : 2

    4 4
    3 4
    2 4
    답 : 2

'코딩가딩가' 카테고리의 다른 글

[JAVA]BOJ 14425, 문자열 집합  (0) 2024.07.28
[JAVA]BOJ 11660, 구간 합 구하기 5  (0) 2024.07.28
[JAVA]BOJ 2910, 빈도 정렬  (0) 2024.07.27
[JAVA]BOJ 18870, 좌표 압축  (0) 2024.07.26
[JAVA]BOJ 1302, 베스트셀러  (0) 2024.07.25