본문 바로가기
백준

Q5_2110(공유기 설치)

by mozzi329 2022. 8. 29.
728x90
 

📌 문제

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

C개의 공유기를 N개의 집에 적당히 설치해서, 가장 인접한 두 공유기 사이의 거리를 최대로 하는 프로그램을 작성하시오.
입력)
첫째 줄에 집의 개수 N (2 ≤ N ≤ 200,000)과 공유기의 개수 C (2 ≤ C ≤ N)이 하나 이상의 빈 칸을 사이에 두고 주어진다.
둘째 줄부터 N개의 줄에는 집의 좌표를 나타내는 xi (0 ≤ xi ≤ 1,000,000,000)가 한 줄에 하나씩 주어진다.
출력)
첫째 줄에 가장 인접한 두 공유기 사이의 최대 거리를 출력한다.
시간 제한 : 2 초
메모리 제한 : 128 MB

📌 문제 분석❗️

❗️공유기는 가장 왼쪽부터 설치해야 가장 많이 설치할 수 있다.

 

❗️모든 집에 공유기를 설치했을 때의 최소 갭을 구할 수 있다.

  • 그러나 최소 갭을 굳이 구하려면 별도의 최소 갭을 구하는 로직을 짜야하므로 시간 복잡도가 올라간다.
    때문에 최소 갭은 1로 설정해서 시작하자.

❗️맨 오른쪽 집 좌표에서 맨 처음 집 좌표를 빼면 최대 갭을 구할 수 있다. 

 

❗️최대 갭과 최소 갭 사이에서 이분 탐색을 진행

❗️현재 집에서 다음 집의 거리(Arr[i] - preValue)가 Gap(mid)보다 크거나 같다면 공유기를 설치할 수 있다.

해당 경우를 카운트 해주자.

❗️카운트 값이 공유기 갯수보다 크거나 같다면,

찾으려는 갭의 크기보다 작거나 같다는 뜻, 해당 결과(Gap)를 변수(result)에 담아주고 startGap 값을 조정해준다.

 

❗️카운트 값이 공유기 갯수보다 작다면,

찾으려는 갭의 크기보다 크다는 뜻, endGap 값을 조정해준다.

 

📌 진행

❗️각각의 변수를 입력받고, 집 좌표를 배열에 담아 이분탐색을 위해 정렬해준다.

        int N = readInt();
        int C = readInt();
        int[] wifiArr = new int[N];
        for (int i = 0; i < N; i++) {
            wifiArr[i] = readInt();
        }
        Arrays.sort(wifiArr);

 

❗️lowGap은 1로 임의 지정, highGap은 맨 오른쪽에서 맨 왼쪽을 뺸 값, result에 만족하는 결과 값(midGap)을 담는다.

        int lowGap = 1;
        int highGap = wifiArr[N - 1] - wifiArr[0];
        int result = 0;

 

❗️wifiArr[i] - preValue(최근에 공유기가 설치된 좌표)와 이분 탐색 중인 midGap을 비교한다.

        while (lowGap <= highGap) {
            int midGap = (lowGap + highGap) / 2;
            int preValue = wifiArr[0];
            int count = 1;
            for (int i = 0; i < N; i++) {
                if (wifiArr[i] - preValue >= midGap) {
                    preValue = wifiArr[i];
                    count += 1;
                }
            }

만약 최근에 공유기가 설치된 지점에서 해당 지점의 거리가 갭보다 크거나 같다면 공유기를 설치할 수 있다는 뜻이다. 따라서 공유기가 설치됐으므로 preValue는 해당 지점의 좌표로 최신화하고, 해당 경우 공유기를 설치했으므로 카운트해준다.

 

❗️공유기 수(C)보다 설치한 공유기 수(count)가 크거나 같다면,

            if (count >= C) {
                lowGap = midGap + 1;
                result = midGap;

찾고자하는 최대 갭보다 작거나 같다는 뜻이다.

따라서 갭의 이분 탐색에서 오른쪽 범위를 탐색해야하므로 lowGap을 midGap+1로 업데이트하고, midGap을 결과 값에 담는다.

 

❗️공유기 수(C)보다 설치한 공유기 수(count)가 작다면,

            } else {
                highGap = midGap - 1;
            }

찾고자하는 최대 갭보다 크다는 뜻이다.

따라서 갭의 이분 탐색에서 왼쪽 범위를 탐색해야하므로 highGap을 midGap - 1 로 업데이트한다.

 

❗️마지막 결과 값(result)를 출력

        System.out.println(result);

 

📌 전체 코드

package level22_이분탐색_.Q5_2110;

import java.io.IOException;
import java.util.Arrays;

public class Main {
    public static void main(String[] args) throws IOException{
        int N = readInt();
        int C = readInt();
        int[] wifiArr = new int[N];
        for (int i = 0; i < N; i++) {
            wifiArr[i] = readInt();
        }
        Arrays.sort(wifiArr);
        int lowGap = 1;
        int highGap = wifiArr[N - 1] - wifiArr[0];
        int result = 0;

        while (lowGap <= highGap) {
            int midGap = (lowGap + highGap) / 2;
            int preValue = wifiArr[0];
            int count = 1;
            for (int i = 0; i < N; i++) {
                if (wifiArr[i] - preValue >= midGap) {
                    preValue = wifiArr[i];
                    count += 1;
                }
            }
            if (count >= C) {
                lowGap = midGap + 1;
                result = midGap;
            } else {
                highGap = midGap - 1;
            }
        }
        System.out.println(result);
    }

    private static int readInt() throws IOException {
        boolean isNegative = false;
        int value = 0;
        while (true) {
            int input = System.in.read();
            if(input == ' ' || input == '\n') {
                return (isNegative) ? -1 * value
                        : value;
            } else if (input == '-') {
                isNegative = true;
            } else {
                value = value * 10 + (input - 48);
            }
        }
    }
}

 

📌 참조

 

댓글