ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준]13392: 구간 나누기2 - JAVA
    문제풀이/백준 2021. 7. 6. 15:56

    [백준]13392: 구간 나누기2

     

    13397번: 구간 나누기 2

    첫째 줄에 배열의 크기 N과 M이 주어진다. (1 ≤ N ≤ 5,000, 1 ≤ M ≤ N) 둘째 줄에 배열에 들어있는 수가 순서대로 주어진다. 배열에 들어있는 수는 1보다 크거나 같고, 10,000보다 작거나 같은 자연수

    www.acmicpc.net

    풀이

    🪑 최댓값의 최솟값! 을 구하는 문제. 이런 문제는 "이분 탐색" 으로 풀 수 있는 문제들이다. (최단거리는 BFS를 떠올리듯..)

     

    먼저 문제의 조건들을 정리해보자.

    • N개의 수를 M개 이하의 구간으로 나눠 구간 점수의 최대 값의 최소값을 구한다.
    • 구간 점수는 구간에 속한 수의 최대값 에서 최소값을 뺀 값이다.
    • N개의 수를 나눌 때는 연속된 순서대로 나눠지면, 각 구간은 한개 이상의 수를 포함한다. (한개도 가능)
    • 수가 하나도 빠짐 없이 구간에 포함되어야 한다.

     

    🔧 이제 문제 풀이 과정을 생각해 보자.

    1. 이분탐색을 진행한다. 이때 탐색하는 범위는 구간에서 발생할 수 있는 최소 ~ 최대값 사이이며, 탐색에서 사용하는 중앙값이 문제에서 구하고자 하는 최대값의 최소값이 된다.
    2. mid가 최소가 될 수 있도록 M개 이하로 나눌 수 있는지 확인한다.
    3. 나눌 수 있다면, 더 작은 범위를 탐색한다.
    4. 나눌 수 없다면, 더 큰 범위를 탐색한다.

     

    🔹 이분탐색을 진행한다.

    - 범위 지정을 위해 입력받는 값의 최소, 최대값을 저장해 주었다. 최소한의 범위만 탐색해 주기 위함이다.

    - mid 값이 문제에서 구하고자 하는, 최대 값의 최속값이 된다.

    - mid로 m개 이하의 구간으로 나눌 수 있는지 여부에 따라 탐색 범위를 조정해 주었다.

     

    🔹 mid가 최소가 될 수 있도록 M개 이하로 나눌 수 있는지 확인한다.

    - canDivideByMid 함수를 구현해 주었다.

    - 초기 구간의 개수는 1개이며, 초기 mid, max값은 배열의 첫 번째 값으로 초기화 해 주었다.

    - 반복문을 통해 배열의 구간을 탐색한다. 이때 최대값 - 최소값이 mid보다 커지면 mid가 최소가 될 수 있는 구간이 될 수 없으므로 구간의 개수를 하나 늘려 주고 mid, max값도 현재 값으로 변경해 주며 구간을 나눠준다.

    - 구간의 개수가 M보다 커지면 false를 반환한다.

     

     

    코드

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    import java.util.*;
     
    public class Main {
     
        public static void main(String[] args) {
            Scanner scan = new Scanner(System.in);
     
            int n = scan.nextInt();
            int m = scan.nextInt();
     
            int[] nums = new int[n];
            int min = Integer.MAX_VALUE;
            int max = Integer.MIN_VALUE;
            for(int i = 0; i < n; i++) {
                nums[i] = scan.nextInt();
                min = Math.min(nums[i], min);
                max = Math.max(nums[i], max);
            }
     
            int left = 0;
            int right = max - min;
            while(left <= right) {
                int mid = (left + right) / 2;
                if(canDvideByMid(mid, m, nums)) {
                    right = mid - 1;
                } else {
                    left = mid + 1;
                }
            }
            System.out.println(left);
        }
     
        public static boolean canDvideByMid(int mid, int m, int[] nums) {  
            int countSet = 1;
            
            int min = nums[0];
            int max = nums[0];
            for(int i = 1; i < nums.length; i++) {
                min = Math.min(min, nums[i]);
                max = Math.max(max, nums[i]);
                if((max - min) > mid) {
                    min = nums[i];
                    max = nums[i];
                    countSet++;
                    if(countSet > m) return false;
                }
            }
            return true;
        }
    }
    cs

    '문제풀이 > 백준' 카테고리의 다른 글

    [백준]5710: 전기 요금 - JAVA  (0) 2021.07.13
    [백준]20010: 악덕 영주 혜유 - JAVA  (0) 2021.07.07
    [백준]1042: 거짓말 - JAVA  (0) 2021.07.05
    [백준]14890: 경사로 - JAVA  (0) 2021.07.03
    [백준]10711: 모래성 - JAVA  (0) 2021.07.02

    댓글

Designed by Tistory.