코딩테스트

[백준-1931번 자바/java] 회의실 배정 _디버깅의 눈물

디버깅의 눈물 2022. 10. 21. 15:08

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

 

1931번: 회의실 배정

(1,4), (5,7), (8,11), (12,14) 를 이용할 수 있다.

www.acmicpc.net

 

 

 

 

 

 

회의실 배정 성공

 
시간 제한메모리 제한제출정답맞힌 사람정답 비율
2 초 128 MB 143237 44767 31663 29.563%

문제

한 개의 회의실이 있는데 이를 사용하고자 하는 N개의 회의에 대하여 회의실 사용표를 만들려고 한다. 각 회의 I에 대해 시작시간과 끝나는 시간이 주어져 있고, 각 회의가 겹치지 않게 하면서 회의실을 사용할 수 있는 회의의 최대 개수를 찾아보자. 단, 회의는 한번 시작하면 중간에 중단될 수 없으며 한 회의가 끝나는 것과 동시에 다음 회의가 시작될 수 있다. 회의의 시작시간과 끝나는 시간이 같을 수도 있다. 이 경우에는 시작하자마자 끝나는 것으로 생각하면 된다.

입력

첫째 줄에 회의의 수 N(1 ≤ N ≤ 100,000)이 주어진다. 둘째 줄부터 N+1 줄까지 각 회의의 정보가 주어지는데 이것은 공백을 사이에 두고 회의의 시작시간과 끝나는 시간이 주어진다. 시작 시간과 끝나는 시간은 231-1보다 작거나 같은 자연수 또는 0이다.

출력

첫째 줄에 최대 사용할 수 있는 회의의 최대 개수를 출력한다.

예제 입력 1 복사

11
1 4
3 5
0 6
5 7
3 8
5 9
6 10
8 11
8 12
2 13
12 14

예제 출력 1 복사

4

힌트

(1,4), (5,7), (8,11), (12,14) 를 이용할 수 있다.

 

 

 

 

 


 

 

 

 

 

체크 포인트

 

1. 그리디 알고리즘(Greedy Algorithm) 이용

 

-현재의 가장 최적의 답을 선택해 적합한 결과를 도출해내는 '그리디 알고리즘'을 이용하는 문제이다.

-그리디 알고리즘의 대표적 문제 유형으로는 활동 선택 문제나 거스름돈 문제 등이 있다. 이 문제처럼 스케줄을 최대한 많이 배정하는 문제가 활동 선택 문제 유형에 해당한다.

-'회의는 한번 시작하면 중간에 중단될 수 없으며 한 회의가 끝나는 것과 동시에 다음 회의가 시작될 수 있다'라는 조건에서 그리디 알고리즘의 조건을 확인할 수 있다.

 

 

 

 

2. 회의 종료 시간이 빠른 순으로 정렬(Comparator 정렬 활용)

 

 

// Comparator를 이용한 2차원 배열 오름차순 정렬
Arrays.sort(arr, new Comparator<Integer[]>() {

    @Override
    public int compare(Integer[] o1, Integer[] o2) {

        // 회의 종료 시간이 동일한 경우,
        if(o1[1] == o2[1]){
            // 회의 시작 시간을 기준으로 비교 후 오름차순 정렬
            return o1[0] - o2[0];
        }
        // 회의 종료 시간이 다른 경우,
        else{
            // 회의 종료 시간을 기준으로 오름차순 정렬
            return o1[1] - o2[1];
        }
    }
});

 

-최대 사용할 수 있는 회의의 최대 개수를 구하려면 회의 종료 시간이 빠른 순서로 정렬해야 한다. 

-종료시간이 빠를 수록 주어진 회의 시간 내 더 많은 회의를 진행할 수 있기 때문이다.

-Comparator와 람다식을 이용한 2차원 배열 정렬을 이용해 오름차순 정렬을 할 수 있다.

-회의 종료시간을 기준으로 오름차순 정렬 후, 만약 회의 종료시간이 동일하다면 회의 시작시간을 기준으로 오름차순 정렬을 진행했다.

 

 

 

https://tears-of-debugging.tistory.com/54

 

[java(자바)] 2차원 배열 정렬하기 Comparator, 람다식 _디버깅의 눈물

2차원 배열 정렬하기 Comparator, 람다식 -2차원 배열을 정렬할 때 1)Comparator를 이용한 방법과 2)람다식을 이용한 방법 두 가지를 활용할 수 있다. 1)Comparator를 이용한 이차원 배열의 정렬 int[][] arr = {{

tears-of-debugging.tistory.com

 

 

 

 

3. 이전 회의 종료 시간(prevEnd)과 현재 회의 시작 시간(startPoint)이 겹치지 않도록 한다.

 

 

    	// 이전 회의 종료시간을 담아주는 변수
		prevEnd = arr[0][1];
		// 시작 시 회의 개수 1 추가 처리
    	count++;
		
    	
    	// 0번 이후 회의부터 카운팅 시작
    	for(int i=1; i<N; i++){
    		// 회의 시작 시간
    		startPoint = arr[i][0];
    		
    		// 현재 회의 시작 시간이 이전 회의 종료 시간보다 크거나 같은 경우,
    		if(startPoint>=prevEnd){
    			// 회의 개수 추가
    			count++;
    			// 이전 회의 종료 시간 = 현재 회의 종료 시간
    			prevEnd = arr[i][1];
    		}
    		
    	}

 

-한 회의가 끝나가 다음 회의가 시작될 수 있다는 조건을 충족하기 위해 조건이 필요하다.

-제일 첫 회의는 직접 변수를 입력하고, 두번째 회의(i=1)부터는 for문을 통해서 조건을 비교 후 count 처리를 진행했다.

 

 

 

 

 

 

 

 

 

 

풀이

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public  class Main {
	
	static int prevEnd,startPoint,count;

	static Integer[][] arr;
	
    public static void main(String[] args) throws IOException {
    	
    	BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    	
    	StringTokenizer st = new StringTokenizer(br.readLine());

    	// 회의의 수
    	int N = Integer.parseInt(st.nextToken());
    	
    	// 회의 시작 시간과 끝나는 시간을 담는 2차원 배열
    	arr = new Integer[N][2];
    	
    	// 회의 시간 입력
    	for(int i=0; i<N; i++){
    		st = new StringTokenizer(br.readLine(), " ");
    		arr[i][0] = Integer.parseInt(st.nextToken());
    		arr[i][1] = Integer.parseInt(st.nextToken());
    	}
    	
    	solution(N);
    	
    }
    
    
    static void solution(int N){
    	
    	// Comparator를 이용한 2차원 배열 오름차순 정렬
    	Arrays.sort(arr, new Comparator<Integer[]>() {

			@Override
			public int compare(Integer[] o1, Integer[] o2) {
				
				// 회의 종료 시간이 동일한 경우,
				if(o1[1] == o2[1]){
					// 회의 시작 시간을 기준으로 비교 후 오름차순 정렬
					return o1[0] - o2[0];
				}
				// 회의 종료 시간이 다른 경우,
				else{
					// 회의 종료 시간을 기준으로 오름차순 정렬
					return o1[1] - o2[1];
				}
			}
		});

    	// 이전 회의 종료시간을 담아주는 변수
		prevEnd = arr[0][1];
		// 시작 시 회의 개수 1 추가 처리
    	count++;
		
    	
    	// 0번 이후 회의부터 카운팅 시작
    	for(int i=1; i<N; i++){
    		// 회의 시작 시간
    		startPoint = arr[i][0];
    		
    		// 현재 회의 시작 시간이 이전 회의 종료 시간보다 크거나 같은 경우,
    		if(startPoint>=prevEnd){
    			// 회의 개수 추가
    			count++;
    			// 이전 회의 종료 시간 = 현재 회의 종료 시간
    			prevEnd = arr[i][1];
    		}
    		
    	}
    	
    	System.out.println(count);
    }
    

} // end of Main