[이것이 코딩 테스트다 with Python] 공유기 설치(Java)
Goal
“이것이 코딩 테스트다 with Python” 교재의 문제를 분석하고 코드와 함께 이해해보기 위한 글입니다.
[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)가 한 줄에 하나씩 주어진다.
출력
첫째 줄에 가장 인접한 두 공유기 사이의 최대 거리를 출력한다.
문제 분석
가장 인접한 두 공유기 사이가 최대 거리가 되게 공유기를 배치하는 방법을 선택하기 어려운 문제입니다.
공유기 사이의 최소 거리에 따라 설치할 수 있는 공유기 수가 정해진다는 상관관계를 이용해 최소 거리값 중에 최대값을 찾아낼 수 있도록 이진 탐색을 구현해서 풀 수 있습니다.
이진 탐색을 구현하는 방식은 아래와 같습니다.
- 첫 번째
(i)
집에 공유기를 설치하고 가장 작은 좌표와 가장 큰 좌표의 차이의 중앙값을 최소 거리로 지정합니다. - 첫 번째
(i)
공유기로부터 최소 거리 이상의 거리에 있으면서 동시에 가장 가까운 집에 두 번째(i+1)
공유기를 설치합니다. - 마지막 집까지 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;
}
}