반응형
문제
지민이는 N개의 물병을 가지고 있다. 각 물병에는 물을 무한대로 부을 수 있다. 처음에 모든 물병에는 물이 1리터씩 들어있다. 지민이는 이 물병을 또 다른 장소로 옮기려고 한다. 지민이는 한 번에 K개의 물병을 옮길 수 있다.
하지만, 지민이는 물을 낭비하기는 싫고, 이동을 한 번보다 많이 하기는 싫다. 따라서, 지민이는 물병의 물을 적절히 재분배해서, K개를 넘지 않는 비어있지 않은 물병을 만들려고 한다.
물은 다음과 같이 재분배 한다. 먼저 같은 양의 물이 들어있는 물병 두 개를 고른다. 그 다음에 한 개의 물병에 다른 한 쪽에 있는 물을 모두 붓는다. 이 방법을 필요한 만큼 계속 한다.
이런 제약 때문에, N개로 K개를 넘지않는 비어있지 않은 물병을 만드는 것이 불가능할 수도 있다. 다행히도, 새로운 물병을 살 수 있다. 상점에서 사는 물병은 물이 1리터 들어있다.
예를 들어, N=3이고, K=1일 때를 보면, 물병 3개로 1개를 만드는 것이 불가능하다. 한 병을 또다른 병에 부으면, 2리터가 들어있는 물병 하나와, 1리터가 들어있는 물병 하나가 남는다. 만약 상점에서 한 개의 물병을 산다면, 2리터가 들어있는 물병 두 개를 만들 수 있고, 마지막으로 4리터가 들어있는 물병 한 개를 만들 수 있다.
예제 입력 1
3 1
예제 출력 11
예제 입력 2
13 2
예제 출력 23
예제 입력 3
1000000 5
예제 출력 315808
제약조건
✅ 첫째 줄에 N과 K가 주어진다. N은 10^7보다 작거나 같은 자연수이고, K는 1,000보다 작거나 같은 자연수이다.
✅ 첫째 줄에 상점에서 사야하는 물병의 최솟값을 출력한다. 만약 정답이 없을 경우에는 -1을 출력한다.
문제풀이
public class Main {
public static void main(String[] args) throws IOException {
// 1. 변수 선언 및 초기화
PriorityQueue<Integer> pq = new PriorityQueue<>();
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 count = 0, result = 0, amount = 1;
// 2. 물병 크기 구하기
while (n > 0) {
if ((n & 1) == 1) {
pq.add(amount);
count++;
}
amount *= 2;
n /= 2;
}
// 3. 조건을 만족할 때까지 가장 작은 물병 두 개를 합침
while (count > k) {
if (pq.size() >= 2) {
// 가장 작은 두 개 물병 꺼내기
int first = pq.poll();
int second = pq.poll();
// 꺼낸 두 물병이 같으면 카운트 다운
if (first == second) {
pq.add(first + second);
count--;
continue;
}
// 구매해야 하는 물병 수 누적
result += (second - first);
// 채운 물병을 다시 적재
pq.add(second);
pq.add(second);
}
}
// 4. 출력
System.out.println(result);
}
}

- 우선순위 큐를 통해 그리디스럽게 풀었다.
- 우선순위 큐가 내부적으로 어떻게 동작하는지는 다음 블로그에서 확인하였다.
[Java] PriorityQueue(우선순위 큐) 클래스 사용법 & 예제 총정리
우선순위 큐(Priority Queue)란? 일반적으로 큐는 데이터를 일시적으로 쌓아두기 위한 자료구조로 스택과는 다르게 FIFO(First In First Out)의 구조 즉 먼저 들어온 데이터가 먼저 나가는 구조를 가집니다
coding-factory.tistory.com
- 나머지 연산을 비트 연산자를 통해 효율적으로 개선하였다.
- if (n & 1 == 1)과 if (n % 2 == 1) 조건 모두 같은 결과를 기대할 수 있다.
- 그런데 비트 연산자를 통한 방법이 CPU 명령어 수준에서 최적화되므로 더 빠르다고 한다.
- 반복문에서 반복 횟수가 늘어날 수록 빛을 발할 것이다.
코드가 조금 불필요하게 길어진 느낌이 있기는 하지만.. 이번에는 선택과 집중을 위해 눈물을 머금고 넘어가려고 한다. 🤪
'개발 > 코딩테스트' 카테고리의 다른 글
[Beakjoon] 1978. 소수 찾기 #B2 #Java (4) | 2025.03.26 |
---|---|
[Baekjoon] N과 M (1 ~ 12) #BackTracking (2) | 2025.03.17 |
[Leetcode] 101. Symmetric Tree #Easy #Java (1) | 2025.03.11 |
[LeetCode] 100. Same Tree #Easy #Java (0) | 2025.03.08 |
[LeetCode] 94. Binary Tree Inorder Traversal #Easy #Java (0) | 2025.03.08 |