문제
다솜이는 유료 고속도로를 가지고 있다. 다솜이는 현재 고속도로에 휴게소를 N개 가지고 있는데, 휴게소의 위치는 고속도로의 시작으로부터 얼만큼 떨어져 있는지로 주어진다. 다솜이는 지금 휴게소를 M개 더 세우려고 한다.
다솜이는 이미 휴게소가 있는 곳에 휴게소를 또 세울 수 없고, 고속도로의 끝에도 휴게소를 세울 수 없다. 휴게소는 정수 위치에만 세울 수 있다.
다솜이는 이 고속도로를 이용할 때, 모든 휴게소를 방문한다. 다솜이는 휴게소를 M개 더 지어서 휴게소가 없는 구간의 길이의 최댓값을 최소로 하려고 한다. (반드시 M개를 모두 지어야 한다.)
예를 들어, 고속도로의 길이가 1000이고, 현재 휴게소가 {200, 701, 800}에 있고, 휴게소를 1개 더 세우려고 한다고 해보자.
일단, 지금 이 고속도로를 타고 달릴 때, 휴게소가 없는 구간의 최댓값은 200~701구간인 501이다. 하지만, 새로운 휴게소를 451구간에 짓게 되면, 최대가 251이 되어서 최소가 된다.
입력
첫째 줄에 현재 휴게소의 개수 N, 더 지으려고 하는 휴게소의 개수 M, 고속도로의 길이 L이 주어진다. N은 100보다 작거나 같으며, M도 100보다 작거나 같다. L은 100보다 크거나 같고, 1000보다 작거나 같은 정수이다. 모든 휴게소의 위치는 중복되지 않으며, N+M은 L보다 작다. 둘째 줄에, 휴게소의 위치가 공백을 사이에 두고 주어진다.
출력
첫째 줄에 M개의 휴게소를 짓고 난 후에 휴게소가 없는 구간의 최댓값의 최솟값을 출력한다.
🌈 풀이 후기
- K번째 수와 동일하게 이분 탐색을 응용한 Parametric Search 문제입니다.
- 처음에 이 문제를 잘 이해하지 못했는데 아래 블로그 글을 보고 이해하게 되었습니다. 0~1000 사이에서 500이 조건을 만족한다면 0~499는 확인하지 않고 500~1000을 탐색하면 됩니다.
👩🏫 문제 풀이
알고리즘 - Parametric Search ( 이분탐색 유사)
-
휴게소의 거리이기 때문에 처음 0, 마지막 L을 추가로 넣어줍니다. 그리고 정렬한 뒤에 이분 탐색을 시작합니다.
-
휴게소 사이 거리가 Mid라고 했을때, 현재 세워진 휴게소 사이에 새로 끼워 넣을 수 있는 휴게소 수의 합을 체크해서 M보다 크다면 조건을 충족하기 때문에 더 넓은 범위에서 탐색합니다.
-
만약에 조건에 부합하지 않는다면 범위를 낮춰서 탐색합니다.
본 문제의 예시를 보면 다음과 같습니다.
mid: 400 sum: 0, L: 0 right: 800
⇒ 휴게소 거리를 400이라고 했을 경우, 세울 수 있는 휴게소 수는 0개이다. 조건을 충족하지 않기에 범위를 낮춰서 검사한다.
mid: 199 sum: 1, L: 0 right: 399
mid: 99 sum: 5, L: 0 right: 198
mid: 49 sum: 12, L: 0 right: 98
⇒ 휴게소 거리를 49라고 했을 경우, 세울 수 있는 휴게소 수는 12개이다. 따라서 조건을 충족하기 때문에 범위를 넓혀서 검사한다.
mid: 74 sum: 6, L: 50 right: 98
mid: 61 sum: 10, L: 50 right: 73
mid: 67 sum: 8, L: 62 right: 73
mid: 70 sum: 7, L: 68 right: 73
mid: 68 sum: 8, L: 68 right: 69
mid: 69 sum: 8, L: 69 right: 69
⇒ left에 +1을 하면 더이상 left가 right보다 작거나 같지 않기에 반복문을 빠져나간다.
package com.Boj.Day5;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
//이분 탐색 (Parametric search)
public class BOJ_G5_1477_휴게소세우기 {
static int N, M, L;
static int[] rest;
static int left, right;
static int result = 0;
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());
M = Integer.parseInt(st.nextToken());
L = Integer.parseInt(st.nextToken());
rest = new int[N + 2];
st = new StringTokenizer(br.readLine(), " ");
for (int i = 1; i <= N; i++) {
rest[i] = Integer.parseInt(st.nextToken());
}
// 도로의 시작 , 끝도 휴게소로 넣어줘야 한다.
rest[0] = 0;
rest[N + 1] = L;
Arrays.sort(rest);
binarySearch();
System.out.println(left);
}
// 0 82 201 411 555 622 755 800
// 휴게소 m개를 추가로 지었을 때, 각 휴게소 사이의 거리의 최대값이 d 이하가 되게 만들 수 있는가? => T / F
// M개를 설치했을 때 각 휴게소끼리의 거리의 최대값을 mid라고 하자. 조건을 충족하는 최적의 mid를 찾아가는 방식이다.
// 만약 400일때 조건을 충족한다면 0~399는 볼필요도 없다. 401부터 최대값을 찾아나간다.
private static void binarySearch() {
left = 0;
right = L;
while (left <= right) {
int mid = (left + right) / 2;
int sum = 0;
for (int i = 1; i < N + 2; i++)
// 휴게소 사이 거리가 mid라고 했을때, 현재 세워진 휴게소 사이에 새로 끼워 넣을 수 있는 휴게소 수.
sum += (rest[i] - rest[i - 1] - 1) / mid;
// System.out.println("mid: "+mid+" sum: "+sum+", L: "+left+" right: "+right);
// 현재 mid의 거리 차이가 가능하다면 => 더 최대값을 찾기 위해 더 넓은 범위 탐색.
if (sum > M)
left = mid + 1;
// 더 적게 세워야 하면 간격을 줄인다.
else
right = mid - 1;
}
}
}
'Algorithm(알고리즘) > BOJ(백준) 문제풀이' 카테고리의 다른 글
[Java][백준 1103][dfs + dp] 게임 (0) | 2021.04.06 |
---|---|
[Java] [백준 1300][이분 탐색, Parametric Search] K번째 수 (0) | 2021.03.01 |
[Java] [백준 2075][우선순위큐] N번째 큰 수 (0) | 2021.02.27 |
[Java] [백준 11659][누적합] 구간합 4 (0) | 2021.02.27 |
[Java] [백준 2003][투 포인터] 수들의합 2 (0) | 2021.02.27 |