[백준 2343] 기타 레슨(Java)

최민길(Gale)·2023년 2월 4일
1

알고리즘

목록 보기
31/172

문제 링크 : https://www.acmicpc.net/problem/2343

이 문제는 이진 탐색을 이용하여 풀 수 있습니다. 완전 탐색으로 문제를 풀 경우 N = 100,000이어서 O(N^2) = 약 10,000,000,000으로 시간 초과가 발생하기 때문에 이진 탐색으로 진행하게 되면 O(log(N^2))으로 시간을 단축시킬 수 있습니다.

이진 탐색의 경우 문제 조건을 만족시킬 수 있는 max값과 min값을 설정하여 두 값의 중앙값을 정답이라고 가정하여 로직에 대입한 후 조건에 따라 max와 min 값을 수정하여 범위를 좁혀나가면서 값을 찾아가는 방식입니다. 이 문제에서 가능한 정답의 범위는 모든 수의 합이 최대, 단일 수의 최댓값이 최소로의 범위를 가지게 됩니다. 따라서 해당 범위 내에서 중앙값을 구한 후 로직에 대입하여 처리하시면 되겠습니다.

다음은 코드입니다.

import java.io.*;
import java.util.*;

public class Main{
    static int N,M;
    static long sum,cnt;
    static ArrayList<Integer> req = new ArrayList<>();

    public static void main(String[] args)throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());

        // 이진 탐색 사용
        // 완전탐색으로 진행할 경우 시간 초과

        // N = 100,000 * 10,000 하면 int 범위 초과하므로 long으로 설정
        long max = 0;
        long min = 0;

        st = new StringTokenizer(br.readLine());
        for(int i=0;i<N;i++){
            req.add(Integer.parseInt(st.nextToken()));

            // max = 모든 수의 합
            max += req.get(i);

            // min = 단일 수의 최댓값
            if(min < req.get(i)) min = req.get(i);
        }

        // 이진 탐색 시작
        // min과 max의 격차를 줄여나가면서 탐색
        while(min<=max){
            // 중앙값 : min과 max의 평균
            long mid = (min + max)/2;
            sum = 0;
            cnt = 0;

            for(int i=0;i<N;i++){
                // 만약 기존 합에서 현재 값을 더한 값이 mid보다 크다면 cnt++ 후 sum 초기화
                if(sum + req.get(i) > mid){
                    cnt++;
                    sum = 0;
                }
                // sum에 값들을 지속적으로 더해주기
                sum += req.get(i);
            }

            // 만약 sum이 0이 아니라면 cnt++
            if(sum != 0) cnt++;

            // 만약 cnt가 M보다 작거나 같다면 max를 줄여 다음 mid 값을 줄이기
            if(cnt<=M) max = mid-1;
            // 만약 cnt가 M보다 크다면 min을 늘려 다음 mid 값을 늘리기
            else min = mid+1;
        }

        // min에 최종 결과 저장되므로 min 출력
        System.out.println(min);
    }
}

profile
저는 상황에 맞는 최적의 솔루션을 깊고 정확한 개념의 이해를 통한 다양한 방식으로 해결해오면서 지난 3년 동안 신규 서비스를 20만 회원 서비스로 성장시킨 Software Developer 최민길입니다.

0개의 댓글