
메모리: 122888 KB, 시간: 212 ms
이분 탐색, 매개 변수 탐색
도현이의 집 N개가 수직선 위에 있다. 각각의 집의 좌표는 x1, ..., xN이고, 집 여러개가 같은 좌표를 가지는 일은 없다.
도현이는 언제 어디서나 와이파이를 즐기기 위해서 집에 공유기 C개를 설치하려고 한다. 최대한 많은 곳에서 와이파이를 사용하려고 하기 때문에, 한 집에는 공유기를 하나만 설치할 수 있고, 가장 인접한 두 공유기 사이의 거리를 가능한 크게 하여 설치하려고 한다.
C개의 공유기를 N개의 집에 적당히 설치해서, 가장 인접한 두 공유기 사이의 거리를 최대로 하는 프로그램을 작성하시오.
첫째 줄에 집의 개수 N (2 ≤ N ≤ 200,000)과 공유기의 개수 C (2 ≤ C ≤ N)이 하나 이상의 빈 칸을 사이에 두고 주어진다. 둘째 줄부터 N개의 줄에는 집의 좌표를 나타내는 xi (0 ≤ xi ≤ 1,000,000,000)가 한 줄에 하나씩 주어진다.
첫째 줄에 가장 인접한 두 공유기 사이의 최대 거리를 출력한다.
n개중 c개를 골라 나올수 있는 모든 조합을 가져와서
각각 배열 속 모든 차이중 최소값을 구한뒤,
그 최소값들중 최대값을 출력한다
와 같은 논리로 접근하는편이 편하다고 생각했고, 실제로 그 코드를 구현해서 제출도 해보았다. 아래는 그 코드다.
import sys
from itertools import combinations
input = sys.stdin.readline
n, c = map(int, input().split())
n_list = []
for i in range(n):
a = int(input())
n_list.append(a)
n_list.sort()
def min_distance(combination):
min_dist = float('inf')
for i in range(1, len(combination)):
distance = combination[i] - combination[i - 1]
if distance < min_dist:
min_dist = distance
return min_dist
max_min_distance = 0
for combination in combinations(n_list, c):
min_dist = min_distance(combination)
if min_dist > max_min_distance:
max_min_distance = min_dist
print(max_min_distance)
실제로 구현은 잘 됐지만, 제출과정 속에서 시간 초과가 나왔다. 뿐만아니라, 하나하나 찾으면서 순차탐색을 통해서도 충분히 구현할수 있다고 생각했지만, 시간복잡도와 관련있는 시간초과가 나오면서 이분탐색을 적용해 풀어야 한다는걸 알게됐다.
for i in range(n):
if n_list[i] - target >= mid:
count = count + 1
target = n_list[i] min(n_list) 값이 target이기 때문에, 예제로 치면 맨 앞쪽의 1이 초반 값이 되고, 그다음 뽑아온 n_list 값과의 차이를 mid 와 비교를 해주게 된다. 우선 내가 정한 mid값은 중앙값 이였고, 이를 만족하지 않는다면, 다음 i 로 넘아간다. 만족하게 되면, 공유기 개수인 count를 추가하며 끝값까지 가게되는데, 여기서 최대로 만들수 있는 공유기의 개수가 정해진체로 count 에 담기게 된다. 이 count값에 c와 일치하거나, c와 더 많다는(통나무문제와 비슷한 원리) 이분탐색문을 적용해주게되면, 문제를 만족하는 코드를 작성할수 있게 된다. 이해는 잘 됐지만.. 이게 맞는걸까? 문제를 미리 풀어보거나, 비슷한 문제를 풀어보지 않았다면 아무것도 없는 상태에서 풀어내기 쉽지 않을것 같다. 실제로 1시간반… 정도를 고민했으니, 코딩테스트에서 이 문제를 만나게 된다면 아직은 많이 해맬것 같다. chat gpt를 통해 구현해 내긴 했지만, 다른 문제들만큼 깔끔하게 이해하진 못한체로 구현했어서 아쉬움이 많이 남는다. 유형을 익히는게 중요할것 같다.#https://www.acmicpc.net/problem/2110
#공유기 설치
#2110
import sys
input = sys.stdin.readline
n, c = map(int, input().split())
n_list = []
for i in range(n):
a = int(input())
n_list.append(a)
# print(n_list)
n_list.sort()
start = 0
end = max(n_list)- min(n_list)
result = 0
# for i in range(c):
# n중에 c만큼을 정할것임
# 그 c들중의 거리차이중 가장 작은것이 최대가 되게끔 하도록 해야함
# 출력은 그 작은것중 최대인것을 출력할예정
while start <= end:
mid = (start + end) // 2
# count = 0
# target = 0
count = 1
target = min(n_list)
for i in range(n):
if n_list[i] - target >= mid:
count = count + 1
target = n_list[i]
# if count == c:
# result = mid
# if count > c:
# start = mid + 1
if count >= c:
result = mid
start = mid + 1
elif count < c:
end = mid - 1
# if n_list[mid] == target:
# elif n_list[mid] > target:
# start = mid +1
# elif n_list[mid] < target:
# end = mid + 1
print(result)