Study/Baekjoon

Baekjoon1931*: 회의실 배정, 시간 초과와 그리디 알고리즘

devyoseph 2021. 11. 1. 02:10

문제

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

입력

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

출력

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

 

풀이1

제한조건을 확인한다. 시작시간과 끝나는 시간의 최대 간격은 2의 31승으로 매우 커보이지만 int의 최대범위다. 회의의 수는 10만까지 가능하고 주어진 회의시간들은 오름차순 또한 아니다.

동적계획법을 활용하여 매 항마다 최대 회의시간을 기록한다. 현재항 i에서 자기보다 이전항 중 시간이 겹치지 않는 회의를 찾는다.

시간이 겹치지 않는 회의 중 최대값을 가져와 1을 더한다

1 4 1
3 5 1
0 6 1
5 7 2
3 8 1
5 9 2
import java.util.Scanner;
public class Main {
	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
		int N = sc.nextInt();
		int[][] dp = new int[N+1][3];
		dp[0][2]=0;
		for(int i=1;i<N+1;i++){
			dp[i][0]=sc.nextInt();
			dp[i][1]=sc.nextInt();
			for(int j=0;j<i;j++) {
				if(dp[i][0]>=dp[j][1] || dp[i][1]<=dp[j][0]) {
					dp[i][2]=Math.max(dp[i][2], dp[j][2]+1);
                }}}
		System.out.print(dp[N][2]);
    }}

*시간 초과가 나온다. 이러한 동적 계획법을 보완하기 위해 그리디 알고리즘을 사용한다고 한다.

 

풀이2

그리드 알고리즘의 활동 선택 문제(Activity Selection problem) 유형이다. 위와 같이 동적계획법을 통해 최대값을 계속 구해나가며 구할 수 있지만 시간이 오래걸린다는 단점이 존재한다. 이를 더 단순화하기 위해 회의가 가장 먼저 끝나는 순서대로 정렬한 뒤 회의들을 이어 붙이는 식으로 한다.

[ 가장 먼저 끝나는 회의를 선택 ] →[ 그 뒤에 겹치지 않으면서 가장 먼저 끝나는 회의를 선택 ]을 반복하는 것이다.

이를 위해 정렬을 해야하는데, 이중배열의 정렬은 Arrays.sort의 compare을 사용한다.

정렬을 한 후에는 이미 시간 순으로 나열되어있기 때문에 반복문을 한 번 돌리면서 값을 구할 수 있게 된다.

import java.util.*;
public class Main {
	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
		int N = sc.nextInt();
		int[][] arr = new int[N][2];
		int sum=0;
		int left=0;
		for(int i=0; i<N;i++) {
			arr[i][0]=sc.nextInt();
			arr[i][1]=sc.nextInt(); //배열에 값을 넣어준다
		}
		Arrays.sort(arr, (o1, o2) -> { //정렬하는 코드
			if(o1[1] == o2[1]) {
		    return Integer.compare(o1[0],o2[0]);}
		else{
			return Integer.compare(o1[1],o2[1]); } });
	
    for(int i=0; i<N;i++) {
			if(arr[i][0]>=left) { //어차피 끝나는 시간 순차적으로 배열되어있기 때문에
				left=arr[i][1];   //오른쪽으로 가면서 겹치지 않는 구간을 만나면 바로 추가해준다
				sum++;
			}
	}
	System.out.print(sum);
    }}

'Study > Baekjoon' 카테고리의 다른 글

Baekjoon13305*: 주유소  (0) 2021.11.02
Baekjoon1541: 잃어버린 괄호  (0) 2021.11.02
Baekjoon11399: ATM  (0) 2021.11.01
Baekjoon11047: 동전 0  (0) 2021.10.31
Baekjoon12865: 평범한 배낭  (0) 2021.10.31