ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 1561 놀이 공원
    백준/이분탐색 2022. 5. 28. 23:06

     

    1. 풀이

     

    다른 블로그를 참고했다.

     

    예제 3을 가지고 설명하겠다.

     

    22 5
    1 2 3 4 5

     

     

    1) 시간에 따른 놀이기구 이용 상황

     

    아이들이 22명 있고, 놀이기구가 5개 있다.

    시간에 따른 아이들의 놀이기구 이용 상황을 표로 나타내면 다음과 같다.

     

    즉, 맨 처음 0분에는 5명의 아이들이 각 놀이기구에 탑승한다.

    1분 뒤에는 1번 놀이기구를 이용할 수 있고,

    2분 뒤에는 1번, 2번 놀이기구를 이용할 수 있다.

     

     

    위에서 보면 아이들이 놀이기구를 모두 탑승했을 때의 시간이 8분이다.

    이 시간을 이분탐색을 이용하여 찾아낼 것이다. 

     

    8이라는 숫자로 어떻게 정답, 즉 마지막 아이가 타게 되는 놀이기구 번호를 찾는지 살펴보자

     

    일단 8분보다 1분 작은 7분동안 몇 명의 아이들이 놀이기구에 탑승하는지 살펴보자.

    일단 0분에는 각 놀이기구를 모두 이용할 수 있기 때문에 5명의 아이들이 탑승한다.

    1분부터 7분까지 각 놀이기구에 탑승하는 아이들 수는 아래의 식으로 알 수 있다.

     

    => 7분/ 각 놀이기구의 운행시간 (결과에서 정수부분만 이용)

     

    1번 놀이기구 : 7/1 = 7명

    즉, 1분부터 7분까지 7명이 탈 수 있다.

     

    2번 놀이기구 : 7/2 = 3.5 => 3명

    즉, 1분부터 7분까지 3명이 탈 수 있다.

     

    때문에 0분부터 7분까지 놀이기구에 탑승하는 아이들의 수는

    총 19명이 됨을 알 수 있다.

     

    이제 정답을 찾기 위해

    22번째 아이가 탑승하는 놀이기구 번호를 찾아야 한다.

    20, 21, 22 번째 아이가 8분이 되면 놀이기구에 탑승한다.

    그런데 5개의 놀이기구 중 1번, 2번, 4번 놀이기구에 탑승하고 있다.

     

    1번 놀이기구의 운행시간은 1분,

    2번 놀이기구의 운행시간은 2분

    이런 식인데

     

    8로 1,2,3,4,5 를 나누었을 때 나머지가 0인 것은 1,2,4임을 알 수 있다.

    즉, 각 시간에 탑승할 수 있는 놀이기구는 

     

    분/ 운행시간 => 나머지가 0인 경우 

     

    그렇다면 8로 나눠서 나머지가 0인 마지막 놀이기구 번호를 출력하면 답이된다.

     

     

    2) 이분탐색

    이분탐색을 통해 8분,

    즉 모든 아이들이 놀이기구에 탑승했을 때의 시간을 찾아보자.

     

    변수 left, right, middle 을 이용한다.

    이 변수들은 놀이기구 이용시간을 의미한다.

     

    처음에

    left = 0,

    right = (N*max) / M

    middle = (left+right) / 2

     

    right 는 모든 아이들이 놀이기구를 탑승했을 때 걸릴 최대 시간을 계산해본다.

    max 는 놀이기구 운행시간 중 최고값, 여기서는 5가 된다.

     

    즉, 22명의 아이들이 놀이기구를 이용하는데,

    모든 놀이기구의 운행시간을 5분이라 하고 계산하는 것이다.

     

    22명이 5분씩 걸리는 놀이기구를 타므로,

    22*5 를 해야되고

    이런 놀이기구가 5개 있으므로

    (22*5) / 5

    해준다고 생각하면 된다.

     

    2-1) while 문

     

    이 예제에서 

    left = 0, right = 22, middle = 11 이 된다.

     

    그러면 middle 이라는 시간에 놀이기구에 탑승할 수 있는 아이들의 수를 세어본다.

    0분에는 M 명, 즉 5명이 타므로 일단 5를 더해준다.

     

    => 탑승한 아이들의 수 : 5

     

    그 후 1분부터 middle 시간동안 각 놀이기구에 탑승할 수 있는 아이들의 수는 

    middle/ 각 놀이기구 운행시간 

    이라고 위에서 설명했다.

     

    => 탑승한 아이들 수 : 5 + middle / 1 + middle/2 + middle/ 3 + middle /4 + middle/5 

    = 5 +11+ 5+ 3+ 2+ 2

    = 28

     

    그러면 우리가 찾고자 하는 값은 22인데, 이보다 크기 때문에,

    즉 22명의 아이들만 탑승시키면 되는데, 28명이 탑승했기 때문에

    시간을 줄이면 탑승하는 아이들의 수를 줄일 수 있다.

     

    그래서 right = middle -1 로 해준 뒤 다시 이분탐색을 하면 된다.

     

    이런식으로 이분탐색을 해주면서 8을 찾아내면 된다.

     

     

    2. 최종 코드

     

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.StringTokenizer;
    
    public class Main {
    
    	static long N;
    	static int M;
    	static int max;
    	static int time[];
    	static long result;
    	
    	public static void main(String[] args) throws IOException {
    		
    		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    		StringTokenizer st = new StringTokenizer(br.readLine(), " ");
    		N = Long.parseLong(st.nextToken());
    		M = Integer.parseInt(st.nextToken());
    		
    		time= new int [M+1];
    		max = -1;
    		
    		st = new StringTokenizer(br.readLine(), " ");
    		
    		for(int i=1; i<=M; i++) {
    			time[i] = Integer.parseInt(st.nextToken());
    			max = Math.max(max, time[i]);
    		}
    		
    		if(N<=M) {
    			System.out.println(N);
    			return;
    		}
    		
    		result = 0;
    		solve();
    		
    		long sum = M;
    		
    		for(int i=1; i<=M; i++) {
    			
    			sum+= (result-1)/time[i];
    		}
    		
    		for(int i=1; i<=M; i++) {
    			
    			if(result%time[i] ==0) {
    				sum++;
    				
    				if(sum== N) {
    					System.out.println(i);
    					return;
    				}
    			}
    		}
    	}
    	
    	public static void solve() {
    		
    		long left = 0;
    		long right = (N*max)/M;		
    		
    		
    		while(left <= right) {
    			
    			long middle = (left + right) / 2;
    			long number = M;
    			
    			for(int i=1; i<=M; i++) {
    				number+=middle/time[i];
    			}
    		
    			
    			if(number <N)  {
    			
    				left = middle +1;
    				
    			}else {
    					
    				right = middle-1;
    			}
    		}
    		
    		result = left;
    	}
    }

     

     

    참고 블로그 : 

    https://lotuslee.tistory.com/91

     

    [백준 1561번] 놀이 공원 (java)

    1561번: 놀이 공원 첫째 줄에 N(1 ≤ N ≤ 2,000,000,000)과 M(1 ≤ M ≤ 10,000)이 빈칸을 사이에 두고 주어진다. 둘째 줄에는 각 놀이기구의 운행 시간을 나타내는 M개의 자연수가 순서대로 주어진다. 운

    lotuslee.tistory.com

     

     

    '백준 > 이분탐색' 카테고리의 다른 글

    1114 통나무 자르기  (1) 2024.07.23
    20444 색종이와 가위  (0) 2022.06.05
    13702 이상한 술집  (0) 2022.05.04
    12015 가장 긴 증가하는 부분 수열 2  (0) 2022.02.11
    7795 먹을 것인가 먹힐 것인가 (java)  (0) 2022.02.03

    댓글

Designed by Tistory.