성장, 그 아름다운 향연
article thumbnail

 

https://www.acmicpc.net/problem/1477

 

1477번: 휴게소 세우기

첫째 줄에 현재 휴게소의 개수 N, 더 지으려고 하는 휴게소의 개수 M, 고속도로의 길이 L이 주어진다. N은 100보다 작거나 같으며, M도 100보다 작거나 같다. L은 100보다 크거나 같고, 1000보다 작거나

www.acmicpc.net

문제

다솜이는 유료 고속도로를 가지고 있다. 다솜이는 현재 고속도로에 휴게소를 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개의 휴게소를 짓고 난 후에 휴게소가 없는 구간의 최댓값의 최솟값을 출력한다.

 

 


 

문제 이해

 

 

우선 "휴게소가 없는 구간의 길이의 최댓값의 최솟값"은 이분탐색 문제에서 종종 쓰이는 표현인 것 같다.

 

문제의 예시를 살펴보면,

고속도로의 길이가 1000. 현재 휴게소가 200,701,800. 휴게소를 1개 더 세운다.

여기서 휴게소가 없는 구간은 무엇인가?

[200-701], [701-800] 라고 자칫 오인할 수도 있다!

사실 문제 초반에 휴게소의 위치는 고속도로의 시작으로부터 얼만큼 떨어져 있는지 로 명시돼있다.

고속도로의 길이가 1000이라면 0~1000 이므로,

휴게소가 없는 구간의 길이는 [0-200], [200-701], [701-800], [800-1000] 로 이해해야 한다.

 

구간 길이의 최댓값은 501 [200-701] 이다.

하지만 문제에서 명시했듯이 451에 휴게소를 짓게 되면 251 [200-451], 250 [451-701] 이고,

휴게소가 없는 구간의 길이 중에 최댓값이 된다.

 

 

접근 방법

 

 

1) 이분 탐색의 기본은 left(탐색의 시작), right(탐색의 끝) 을 설정하는 것이다.

 

휴게소가 없는 구간의 길이의 최댓값은 어떤 값이 와도 L보다 작기 때문에

 

left = 0

right = L 이 된다.

 

하지만 문제에서 고속도로의 끝에는 휴게소를 세울 수 없다 했으므로,

 

left = 0

right = L-1 으로 설정하자.

 

 

2) 다음으로 탐색 기준이 되는 mid 값을 설정해야 한다.

출력에 나타나 있는 말을 다시 주목해보자.

 

출력
첫째 줄에 M개의 휴게소를 짓고 난 후에 휴게소가 없는 구간의 최댓값의 최솟값을 출력한다.

 

문제의 결과는 휴게소가 없는 구간의 최댓값이다.

그렇기 때문에 이것이 mid 가 되어야 한다.

 

 

 

mid = (left + right) / 2

 

또한 최솟값을 찾아야 하므로 만약 휴게소를 M개 모두 세울 수 있다면~

 

 

(right - 1을 한 이유는 기존에 있던 mid를 이미 탐색한 것이므로 빼줘야 한다.)

 

만약 휴게소 M개를 세우는 횟수가 초과됐다면?

mid 값을 더 확장해야 휴게소를 세우는 횟수를 줄일 수 있으므로~

 

 

 

 

3) mid 를 설정했다면 이제 어떻게 최댓값이면서 최솟값을 찾을 수 있을까?

 

mid는 휴게소가 없는 구간의 최대값이면서 최솟값의 기준이다.

(그리고 편의를 위해 다음과 같이 변수로 설정하겠다.)

- diff = (다음 배열의 원소 - 현재 배열의 원소)

 

1. diff > mid 라면 최대 구간의 길이를 구할 수 있는 상태로 접어든다.

2. diff / mid 를 한 몫은 휴게소를 세우는 횟수가 된다.

 

예를 들어 구간의 길이 = 10, mid = 4 라면

총 길이 10 중에서 4 - 6 으로 쪼갤 수 있고, 6은 4보다 크므로 또 다시

4 2 로 쪼갤 수 있다. 그래서 총 2개를 지을 수 있고, 10 / 4 = 2가 된다. 

  

2-1. 여기서 주의해야 할 점은 휴게소가 있는 위치에 다시 세울 수 없는 조건이 있다.

그래서 diff / mid 의 나머지가 0일 때 mid의 위치도 포함된 것이기 때문에 1을 빼줘야 한다.

 

 

 

전체 코드

 

import java.util.*
private lateinit var arr : IntArray
fun main() = with(System.`in`.bufferedReader()) {
    val (n,m,l) = readLine().split(" ").map { it.toInt() }
    arr = IntArray(n+2)
    arr[0] = 0
    arr[1] = l
    val st = StringTokenizer(readLine(), " ")
    for(i in 2 until n+2) {
        arr[i] = st.nextToken().toInt()
    }
    arr.sort()

    var left = 0
    var right = l-1
    var res = 0

    while (left <= right) {
        val mid = (left + right) / 2
        if(isPossible(mid, m)) {
            right = mid - 1
            res = mid
        } else {
            left = mid + 1
        }
    }
    println(res)
}
private fun isPossible(mid : Int, m : Int) : Boolean {
    var cnt = 0
    for(i in 0 until arr.size-1) {
        val data = arr[i+1] - arr[i]
        
        if(data > mid) {
            cnt += if (data % mid == 0) {
                data / mid - 1
            } else {
                data / mid
            }
        }
    }

    return cnt <= m
}

'algorithm > 탐색' 카테고리의 다른 글

백준 1302) 베스트셀러  (0) 2021.04.26
profile

성장, 그 아름다운 향연

@dev_minoflower

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

profile on loading

Loading...