알고리즘

백준 3079번 입국심사 (JAVA)

박카스마시며코딩 2022. 5. 26. 15:12

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

 

3079번: 입국심사

첫째 줄에 N과 M이 주어진다. (1 ≤ N ≤ 100,000, 1 ≤ M ≤ 1,000,000,000) 다음 N개 줄에는 각 심사대에서 심사를 하는데 걸리는 시간인 Tk가 주어진다. (1 ≤ Tk ≤ 109)

www.acmicpc.net

 

저는 해당 문제를 이분 탐색을 통해서 해결하였습니다.

저는 이분탐색을 작은 값은 1 큰 값은 1,000,000,000 * 1,000,000,000로 하였습니다.

( N=1 , M = 1,000,000,000 , T1 = 1,000,000,000 이렇게 주어진다면 결과 값이 1,000,000,000 * 1,000,000,000 될 것이라 생각하였습니다.)

이분 탐색을 하면서 그 값안에 모든 사람이 검사를 받을 수 있는지 확인하였습니다.

저는 여기서 오류를 범하였습니다.

private static boolean checkInTime(int[] input, int n, int m,long time) {
    long peopleCnt = 0;
    for(int i = 0 ; i < n ; i++){
        peopleCnt += (time / input[i]);

    }
    if(peopleCnt >= m){
        return true;
    }
    return false;
}

저의 처음 해당 시간안에 m명의 사람을 검사할 수 있는지에 대한 함수입니다.

저는 long타입이기 떄문에 왠만하면 오버플로우가 나지 않을 것이라 생각하였습니다.

계산해보니 N = 100,000, M = 1,000,000,000 , T(all) = 1 라 했을 때 최대 값 1,000,000,000 * 1,000,000,000이 time으로 들어오면 peopleCnt가 1,000,000,000 * 1,000,000,000 * 100,000 = 10^24 가 되면서 오버플로우 발생할 여지가 있습니다.

그래서 저는 for문 안에 if문을 넣음으로써 오버플로우가 발생할 여지를 없애고 해결하였습니다.

 

package BOJ.binarysearch;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.util.function.Function;

public class BOJ_3079 {

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine()," ");
        Function<String,Integer> stoi = Integer::parseInt;
        int n = stoi.apply(st.nextToken());
        int m = stoi.apply(st.nextToken());
        int[] input = new int[n];
        for(int i = 0 ; i < n ; i++){
            input[i] = stoi.apply(br.readLine());
        }
        long answer = binarySearch(input,n,m);
        System.out.println(answer);
    }

    private static final long MIN_TIME = 1;
    private static final long MAX_TIME = 1_000_000_000L * 1_000_000_000L;
    private static long binarySearch(int[] input, int n, int m) {
        long result = MAX_TIME;
        long start = MIN_TIME;
        long end = MAX_TIME;
        while(start <= end){
            long mid = (start + end)/2;
//            System.out.println(mid);
            if(checkInTime(input,n,m,mid)){
                end = mid - 1;
                result = mid;
            }else{
                start = mid + 1;
            }
        }
        return result;
    }

    private static boolean checkInTime(int[] input, int n, int m,long time) {
        long peopleCnt = 0;
        for(int i = 0 ; i < n ; i++){
            peopleCnt += (time / input[i]);
            if(peopleCnt >= m){
                return true;
            }
        }
        return false;
    }
}