라떼는말이야

[solved.ac 골드5] 2110_공유기 설치 (파이썬, 이분 탐색) 본문

알고리즘/코딩 테스트

[solved.ac 골드5] 2110_공유기 설치 (파이썬, 이분 탐색)

MangBaam 2022. 4. 9. 03:16
반응형

제한 사항

 

문제

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

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

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

입력

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

출력

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

예제

힌트

공유기를 1, 4, 8 또는 1, 4, 9에 설치하면 가장 인접한 두 공유기 사이의 거리는 3이고, 이 거리보다 크게 공유기를 3개 설치할 수 없다.


나의 풀이

브루트 포스 방식으로 일일이 찾고 비교하는 방식으로는 시간 복잡도가 어마어마하게 커질 수 있다. 이 문제는 이분 탐색으로 접근했다.

초기 세팅

이 문제에서는 공유기 사이의 간격을 이분 탐색으로 찾아나간다.

이 문제에서 하나 이상의 빈 칸이라고 했기 때문에 start(최소 간격)는 1, end(최대 간격)는 마지막 집과 첫 집의 차가 된다.

 

Loop#1

mid 값은 4이다. 즉, 최소 간격이 4일 때 몇 개의 공유기를 놓을 수 있는지 확인한다.

1번 집에 공유기를 놨다면 2, 3번째 집은 간격이 4보다 작기 때문에 공유기를 놓지 않고 8이나 9 둘 중 한 집에 놓을 수 있다.

그럼 이때 놓을 수 있는 공유기의 수는 2개이다.

Loop#2

mid 값은 2이다. 즉, 최소 간격이 2일 때 몇 개의 공유기를 놓을 수 있는지 확인한다.

1번 집에 공유기를 놨다면 2번째 집은 간격이 2보다 작기 때문에 공유기를 놓지 않고 3번째 집에 놓을 수 있다. 그리고 8이나 9 둘 중 한 집에 놓을 수 있다.

그럼 이때 놓을 수 있는 공유기의 수는 3개이다.

공유기를 목표 만큼 놓을 수 있는 간격을 찾았지만 이 간격이 최대 간격인지는 아직 알 수 없다.

그러나 답이 될 수 있기 때문에 별도로 2를 저장해놓는다.

 

Loop#3

mid 값은 3이다. 즉, 최소 간격이 3일 때 몇 개의 공유기를 놓을 수 있는지 확인한다.

1번 집에 공유기를 놨다면 2번째 집은 간격이 3보다 작기 때문에 공유기를 놓지 않고 3번째 집에 놓을 수 있다. 그리고 8이나 9 둘 중 한 집에 놓을 수 있다.

그럼 이때 놓을 수 있는 공유기의 수는 3개이다.

start와 end가 같아졌기 때문에 더 이상 탐색하지 않는다. 그리고 간격이 3 일 때도 3개의 공유기를 놓을 수 있었기 때문에 이전에 따로 저장했던 2와 비교했을 때 3이 더 큰 간격이므로 3을 저장한다.

 

이분 탐색이 완료되었기 때문에 최종적으로 답은 3이 될 수 있다고 생각할 수 있다. 그러나 문제의 조건에서 간과해선 안 될 부분이 있다.

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

실제 공유기의 최대 거리가 답이 될 수 있다. 실제 두 집 사이의 거리를 출력해야 하기 때문에 중간 중간 실제 거리를 저장하는 로직이 필요하다.

 

전체 코드

import sys
input = sys.stdin.readline

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

max_diff = house[-1] - house[0]
start, end = 1, max_diff
answer = 0

while start <= end:
    mid = (start + end) // 2 # 현재 기준 간격
    print(start, end, mid)
    current = house[0] # 현재 기준 집 위치
    count = 1 # 공유기 설치 개수
    diff = max_diff

    for i in range(1, n): # 공유기 사이의 간격이니까 1 ~ n-1
        if house[i] - current >= mid: # 간격이 기준 보다 넓으면 공유기 설치
            diff = min(diff, house[i] - current)
            count += 1
            current = house[i]

    if count >= c: # 공유기 모두 설치 가능, 간격 늘림
        start = mid + 1
        answer = max(answer, diff)
    else: # 공유가 모두 설치 불가, 간격 좁힘
        end = mid - 1
    print(f'count: {count}')

print(answer)

 

채점 결과

반응형
Comments