Post

[이것이 코딩 테스트다 with Python] 공유기 설치(Java)

Goal

“이것이 코딩 테스트다 with Python” 교재의 문제를 분석하고 코드와 함께 이해해보기 위한 글입니다.

image

[Gold IV] 공유기 설치 - 2110

문제 링크

문제 설명

도현이의 집 N개가 수직선 위에 있다. 각각의 집의 좌표는 x1, ..., xN이고, 집 여러개가 같은 좌표를 가지는 일은 없다.

도현이는 언제 어디서나 와이파이를 즐기기 위해서 집에 공유기 C개를 설치하려고 한다. 최대한 많은 곳에서 와이파이를 사용하려고 하기 때문에, 한 집에는 공유기를 하나만 설치할 수 있고, 가장 인접한 두 공유기 사이의 거리를 가능한 크게 하여 설치하려고 한다.

C개의 공유기를 N개의 집에 적당히 설치해서, 가장 인접한 두 공유기 사이의 거리를 최대로 하는 프로그램을 작성하시오.

입력

첫째 줄에 집의 개수 N (2 ≤ N ≤ 200,000)과 공유기의 개수 C (2 ≤ C ≤ N)이 하나 이상의 빈 칸을 사이에 두고 주어진다. 둘째 줄부터 N개의 줄에는 집의 좌표를 나타내는 xi (0 ≤ xi ≤ 1,000,000,000)가 한 줄에 하나씩 주어진다.

출력

첫째 줄에 가장 인접한 두 공유기 사이의 최대 거리를 출력한다.

문제 분석

가장 인접한 두 공유기 사이가 최대 거리가 되게 공유기를 배치하는 방법을 선택하기 어려운 문제입니다.

공유기 사이의 최소 거리에 따라 설치할 수 있는 공유기 수가 정해진다는 상관관계를 이용해 최소 거리값 중에 최대값을 찾아낼 수 있도록 이진 탐색을 구현해서 풀 수 있습니다.

이진 탐색을 구현하는 방식은 아래와 같습니다.

  1. 첫 번째(i) 집에 공유기를 설치하고 가장 작은 좌표와 가장 큰 좌표의 차이의 중앙값을 최소 거리로 지정합니다.
  2. 첫 번째(i) 공유기로부터 최소 거리 이상의 거리에 있으면서 동시에 가장 가까운 집에 두 번째(i+1) 공유기를 설치합니다.
  3. 마지막 집까지 2번 까지의 과정을 반복해 공유기 설치를 마칩니다.

공유기 설치를 마치고, 설치된 공유기 수(cnt)와 설치해야 하는 공유기 수(c)를 비교합니다.

  • cnt > c: 최소 거리가 작기 때문에 설치해야 공유기 수를 초과했다. 그러므로 최소 거리를 늘린다.
  • cnt < c: 최소 거리가 크기 때문에 설치해야 공유기 수에 미달했다. 그러므로 최소 거리를 줄인다.
  • cnt == c: 지금의 최소 거리가 최소 거리 중 최대인지 알 수 없기 때문에, 지금의 최소 거리를 result에 담아주고 최소 거리를 늘린다.

이진 탐색 + 매개 변수 탐색의 과정입니다.

마지막 cnt == c 일 때 최대값이 되도록 구현해내는 것이 포인트입니다.

코드 구현

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
51
public class RouterEquip {

    private static int[] arr;
    private static int n;
    private static int c;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        n = Integer.parseInt(st.nextToken());
        c = Integer.parseInt(st.nextToken());
        arr = new int[n];
        for (int i = 0; i < n; i++) {
            arr[i] = Integer.parseInt(br.readLine());
        }
        Arrays.sort(arr);

        int maxItv = arr[n -1] - arr[0];

        int answer = binarySearch(0, maxItv);
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        bw.write(String.valueOf(answer));
        bw.close();
        br.close();
    }

    private static int binarySearch(int start, int end) {
        int result = 0;
        while (start <= end) {
            int cnt = 1;
            int prv_home = arr[0]; //previous home position
            int mid = (start + end) / 2; //the middle
            //공유기 설치 과정
            for (int i = 0; i < n; i++) {
                if (arr[i] - prv_home >= mid) {
                    cnt++;
                    prv_home = arr[i];
                }
            }

            if (cnt >= c) { //집 사이 거리를 적당히 설정했을 때
                result = mid;
                start = mid + 1;
            } else {
                end = mid - 1;
            }
        }
        return result;
    }
}

This post is licensed under CC BY 4.0 by the author.