알고리즘
[BOJ] - 1로 만들기 / 1463번 (Java)
JinHxxxxKim
2024. 2. 28. 17:40
[BOJ] - 1로 만들기 / 1463번 (Java)
1. 문제 접근
N이 주어졌을 때, 1로 만들기 위한 연산의 최소 횟수를 구하면 된다.
연산을 1. 3으로 나누기, 2. 2로 나누기, 3. 1빼기 총 3가지가 존재한다.
해당 문제는 DP로 풀 수 있지만, 나의 경우에는 BFS를 통해 풀었다.
N을 시작점으로, 도달할 수 있는 번호를 `Queue`에 넣으면서 진행했다.
나누기 연산의 경우, 나누어 떨어질 경우만 고려했고, 공통적으로 기존의 거리(`dist`)와 비교하여 짧은 경우에 한하여 `Queue`에 삽입했다.
int currNum = q.poll();
if (currNum == GOAL)
break;
if (currNum % 3 == 0 && dist[currNum] + 1 < dist[currNum / 3]) {
// 3으로 나누어 떨어지고, 기존의 연산 횟수보다 작을 경우
q.offer(currNum / 3);
dist[currNum / 3] = dist[currNum] + 1;
}
if (currNum % 2 == 0 && dist[currNum] + 1 < dist[currNum / 2]) {
// 2으로 나누어 떨어지고, 기존의 연산 횟수보다 작을 경우
q.offer(currNum / 2);
dist[currNum / 2] = dist[currNum] + 1;
}
if (dist[currNum] + 1 < dist[currNum - 1]) {
// 기존의 연산 횟수보다 작을 경우
q.offer(currNum - 1);
dist[currNum - 1] = dist[currNum] + 1;
}
연산이 숫자를 증가시키는 연산이 없으므로, 방문 배열은 별도로 사용하지 않았다.
2. 코드
package boj;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Queue;
import java.util.StringTokenizer;
/**
* [BOJ] - 1로 만들기 / 1463번
* @author JinHxxxxKim
*
* 1. N번 부터 3으로 나누어 질 경우, 2로 나누어질 경우 분리해서 고려
* 2. 나누어진다면, 기존의 최소 연산횟수와 비교하여 최소값으로 갱신
* 3. 목표 지점(1)을 만나면 종료
*/
public class Sol_1463 {
private static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
private static StringBuilder sb = new StringBuilder();
private static StringTokenizer st;
private static final int GOAL = 1;
private static int N;
private static int[] dist;
public static void main(String[] args) throws Exception {
N = Integer.parseInt(br.readLine().trim());
dist = new int[N + 1];
Queue<Integer> q = new ArrayDeque<>();
// 초기 연산 횟수 초기화
Arrays.fill(dist, Integer.MAX_VALUE);
dist[N] = 0;
q.add(N);
while (!q.isEmpty()) {
int currNum = q.poll();
if (currNum == GOAL)
break;
if (currNum % 3 == 0 && dist[currNum] + 1 < dist[currNum / 3]) {
// 3으로 나누어 떨어지고, 기존의 연산 횟수보다 작을 경우
q.offer(currNum / 3);
dist[currNum / 3] = dist[currNum] + 1;
}
if (currNum % 2 == 0 && dist[currNum] + 1 < dist[currNum / 2]) {
// 2으로 나누어 떨어지고, 기존의 연산 횟수보다 작을 경우
q.offer(currNum / 2);
dist[currNum / 2] = dist[currNum] + 1;
}
if (dist[currNum] + 1 < dist[currNum - 1]) {
// 기존의 연산 횟수보다 작을 경우
q.offer(currNum - 1);
dist[currNum - 1] = dist[currNum] + 1;
}
}
System.out.println(dist[GOAL]);
}
}
3. 디버깅
`Queue`에 삽입할 때, 기존의 연산 횟수보다 작아지는 경우에만 삽입함으로 조금 더 최적화 시킬 수 있었다.