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

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

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

입력

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

출력

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

 

예제 입력 1

5 3
1
2
8
4
9

예제 출력 1

3

 


1차 접근 (2022.1.18 못품)

가능한 집의 좌표가 10억이기 때문에 탐색 범위가 매우 크다. 따라서 이진탐색으로 접근해야한다는 점까지는 캐치를 했는데, 이진 탐색은 특정 값을 찾는 알고리즘인데 공유기 설치를 하는 범위에 어떻게 적용이 되어야 하는지 감이 잘 안 왔다. 얼마 전에 풀었던 떡볶이 떡 자르기 문제와 유사하다는 것까지는 눈치를 챘는데, 그 뒤로 2시간동안 헤매다가 결국 해설을 참고해서 이해를 한다.

 

해설 1

이진 탐색으로 가장 인접한 두 공유기 사이의 거리를 조절해가며, 매번 실제로 공유기를 설치하여 C보다 많은 개수로 공유기를 설치할 수 있는지 체크하여 문제를 해결한다. 다만 가장 인접한 두 공유기 사이의 거리의 최댓값을 찾아야 하므로, C보다 많은 개수로 공유기를 설치할 수 있다면 가장 인접한 두 공유기 사이의 거리의 값을 증가시켜서 더 큰 값에 대해서도 성립하는지 체크하기 위해 다시 탐색을 수행한다. 

 

따라서 매번 가장 인접한 두 공유기 사이의 거리 (gap)의 최소값, 최대값을 계산해주면 될 것이다. 

 

{1,2,4,8,9} 인 수열에 설치해야 하는 공유기의 수 C = 3이라고 해보자.

현재 gap은 1~8 사이의 값이다.  gap = [1,8] 사이

 

1) gap의 값을 중간에 해당하는 4로 설정하면, 공유기를 2개밖에 설치할 수 없다. 따라서 범위를 더 줄일 필요가 있다. 따라서 범위를 [1,3]으로 수정한다. 

2) 범위가 1~3이므로 gap의 값을 중간에 해당하는 2로 설정한다. 이 경우 공유기를 3개 설치할 수 있다. 다만 더 큰 값에 에 대해서도 확인해볼 필요가 있으므로 현재의 gap 값을 저장하고 gap의 값을 증가시켜서 gap이 더 커졌을 때도 가능한지 확인할 필요가 있다. 따라서 범위가 [1,3]인 상태에서 범위를 [3,3]으로 수정한다. 

3) 범위가 3~3이므로 gap의 값을 중간에 해당하는 3으로 설정한다. 이 경우 공유기를 3개 설치할 수 있다. gap이 더 커졌을 떄도 확인해봐야 하나, 현재 gap 범위는 더이상 변경이 불가능하다. 따라서 gap=3이 최적의 경우이다.

--> 솔직히 이코테 책에 있는 풀이 잘 모르겠다. 다른 블로그를 참고했다...

 

해설2

공유기 설치 길이를 움직여(이분 탐색을 통해) 적절한 집에 설치 가능한지 살펴보는 문제.

 

거리가 주어지면 공유기(router)를 몇 개 설치할 수 있는지 계산하는 router_setting 함수

첫번째 집을 start로, 첫집과 끝집의 차이을 end로 둔다

 1) 중간값mid로 충분한 설치 장소를 찾지 못했다면 거리를 줄여주고

 2) 설치된 집이 더 많다면 거리를 늘려준다.

 

Python

# 2022-01-18
# 이코테 ch15 이진 탐색 문제 Q29 공유기 설치
# https://www.acmicpc.net/problem/2110

import sys

input = sys.stdin.readline

n, c = map(int, input().split())
house = [int(input()) for _ in range(n)]
house.sort()

# 해당 거리를 유지하며 공유기를 몇대까지 설치 가능한지
def router_setting(dist):
    count = 1
    cur_house = house[0]  # 시작점 (공유기 설치)
    for i in range(1, n):  # 집 모두를 순회
        # 이전 집에서 해당 거리보다 멀리 떨어진 집이라면
        if cur_house + dist <= house[i]:
            count += 1  # 공유기 설치
            cur_house = house[i]  # 공유기 설치된 집 갱신

    return count


start = 1
end = house[-1] - house[0]  #
answer = 0

while start <= end:
    mid = (start + end) // 2
    if router_setting(mid) >= c:
        answer = mid
        start = mid + 1
    else:
        end = mid - 1

print(answer)

 

회고

이진탐색 진짜 어렵다.... 토폴로지 풀 때랑 비슷한 갑갑함이다. 익숙해질 때까지 부딪혀보자 ㅠㅠ 해설을 한시간동안이나 찾아보고 읽어봤다

+ Recent posts