(BOJ) 1152 물병

1152 물병

  • 분류 : 수학, 구현, 탐욕법, 비트마스킹

문제

지민이는 N개의 물병을 가지고 있다. 각 물병에는 물을 무한대로 부을 수 있다.

처음에 모든 물병에는 물이 1리터씩 들어있다.

지민이는 이 물병을 또 다른 장소로 옮기려고 한다. 지민이는 한 번에 K개의 물병을 옮길 수 있다.

하지만, 지민이는 물을 낭비하기는 싫고, 이동을 한 번보다 많이 하기는 싫다.

따라서, 지민이는 물병의 물을 적절히 재분배해서, K개를 넘지 않는 비어있지 않은 물병을 만들려고 한다.

물은 다음과 같이 재분배 한다.

먼저 같은 양의 물이 들어있는 물병 두 개를 고른다. 그 다음에 한 개의 물병에 다른 한 쪽에 있는 물을 모두 붓는다. 이 방법을 필요한 만큼 계속 한다.

이런 제약 때문에, N개로 K개를 넘지않는 비어있지 않은 물병을 만드는 것이 불가능할 수도 있다.

다행히도, 새로운 물병을 살 수 있다. 상점에서 사는 물병은 물이 1리터 들어있다.

예를 들어, N=3이고, K=1일 때를 보면, 물병 3개로 1개를 만드는 것이 불가능하다.

한 병을 또다른 병에 부으면, 2리터가 들어있는 물병 하나와, 1리터가 들어있는 물병 하나가 남는다.

만약 상점에서 한 개의 물병을 산다면, 2리터가 들어있는 물병 두 개를 만들 수 있고, 마지막으로 4리터가 들어있는 물병 한 개를 만들 수 있다.

입력

첫째 줄에 N과 K가 주어진다. N은 10^7보다 작거나 같은 자연수이고, K는 1,000보다 작거나 같은 자연수이다.

출력

첫째 줄에 상점에서 사야하는 물병의 최솟값을 출력한다. 만약 정답이 없을 경우에는 -1을 출력한다.

예제 입력 1

1
3 1

예제 출력 1

1
1

예제 입력 2

1
13 2

예제 출력 2

1
3

예제 입력 3

1
1000000 5

예제 출력 3

1
15808

Solution

Expander
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
import java.util.*

private var N: Int = 0
private var K: Int = 0

fun main() {
input()
solve()
}

private fun input() = with(Scanner(System.`in`)) {
N = nextInt() // N개의 물병
K = nextInt() // 한 번에 K개의 물병을 옮길 수 있다
}

private fun solve() {
// 상점에서 사야하는 물병의 최솟값을 출력
var result = 0
// K개를 넘지 않는 비어있지 않은 물병을 만들려고 한다.
while (Integer.bitCount(N) > K) {
val bitwise = N and (-N)
result += bitwise
N += bitwise
}
println(result)
}

Point of Thinking

  • 재분배 규칙에 따라 2진수로 치환하는 문제임을 유추할 수 있다.
  • 비트연산을 반복하면서 K보다 1의 개수가 적을 때까지 반복한다.
  • 반복문의 조건에 맞았을 때 사야하는 물병의 개수를 출력하면 Accepted.

References