Post

BOJ 1052 물병

BOJ 1052 물병

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

문제

지민이는 N개의 물병을 가지고 있다. 각 물병에는 물을 무한대로 부을 수 있다. 처음에 모든 물병에는 물이 1리터씩 들어있다. 지민이는 이 물병을 또 다른 장소로 옮기려고 한다. 지민이는 한 번에 K개의 물병을 옮길 수 있다. 하지만, 지민이는 물을 낭비하기는 싫고, 이동을 한 번보다 많이 하기는 싫다. 따라서, 지민이는 물병의 물을 적절히 재분배해서, K개를 넘지 않는 비어있지 않은 물병을 만들려고 한다.

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

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

이런 제약 때문에, N개로 K개를 넘지않는 비어있지 않은 물병을 만드는 것이 불가능할 수도 있다. 다행히도, 새로운 물병을 살 수 있다. 상점에서 사는 물병은 물이 1리터 들어있다.

예를 들어, N=3이고, K=1일 때를 보면, 물병 3개로 1개를 만드는 것이 불가능하다. 한 병을 또다른 병에 부으면, 2리터가 들어있는 물병 하나와, 1리터가 들어있는 물병 하나가 남는다. 만약 상점에서 한 개의 물병을 산다면, 2리터가 들어있는 물병 두 개를 만들 수 있고, 마지막으로 4리터가 들어있는 물병 한 개를 만들 수 있다.


입력

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


출력

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


예제 입력 1

3 1

예제 출력 1

1

예제 입력 2

13 2

예제 출력 2

3

… 이하 예제 생략


코드

문제를 읽고 이해한 후, 출력 조건을 확인했을 때 머리 속에 물음표가 떠올랐다.

아무리 생각해도 정답이 없는 경우가 존재하지 않을 것 같았다.

그런데 정답이 없을 경우의 출력 조건이 주어져 있어서, 한참을 고민하다가 질문 게시판을 확인했다.

그 결과는 정말 김 빠졌다…

다른 사람들도 나 같은 궁금증이 생겨 꽤 많이 질문 글이 올라와 있었다.

요약하자면, 정답이 없다는 것을 생각해 내는 것도 문제 풀이의 일부라는 것이다.

그래도 골드 이상 난이도의 문제를 100개는 넘게 풀어봐서 어느정도 문제들은 맛을 봤다고 생각했지만, 이렇게 오늘 하나 더 배워간다.

문제를 처음 봤을 때는, 물병의 물이 2의 n제곱 형태를 띄고 있어서 비트마스크인가 생각은 해봤지만, 막상 문제를 풀 때는 이 방법으로 풀지는 않았다.

문제를 푼 뒤, 다른 블로그들을 확인했는데 아니나 다를까 비트마스킹으로 푼 글들이 있었다.

이번 문제는 조금 참신했던 것 같다.

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
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int N = Integer.parseInt(st.nextToken());
        int K = Integer.parseInt(st.nextToken());

        int answer = calculateBottlesToBuy(N, K);
        System.out.println(answer);
    }

    static int calculateBottlesToBuy(int N, int K) {
        int bottles = 0;

        while (Integer.bitCount(N) > K) {
            int lowestBit = Integer.lowestOneBit(N);
            bottles += lowestBit;
            N += lowestBit;
        }

        return bottles;
    }
}
This post is licensed under CC BY 4.0 by the author.