Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 | 30 | 31 |
Tags
- 개발자취업
- 코딩테스트
- 코딩테스트준비
- 웹
- 코딩테스트사이트추천
- #코드트리 #코딩테스트 #코테공부 #백트래킹 #알고리즘 기초
- 코드트리
- 연결 리스트
- 인접 행렬
- 프로그래밍 언어
- C
- 자료구조
- 파이썬
- 운영체제
- 코테공부
- 자바
- 개발자루틴
- 항해99
- 프로그래머스
- 알고리즘
- 99클럽
- 자바스크립트
- 1일1코테
- 갭체크
- 데이터베이스
- Java
- 티스토리챌린지
- til
- 오블완
- 플로이드-워셜
Archives
- Today
- Total
와드의 블로그
12852번: 1로 만들기 2 본문
문제
정수 X에 사용할 수 있는 연산은 다음과 같이 세 가지입니다.
- X가 3으로 나누어 떨어지면, 3으로 나눕니다.
- X가 2로 나누어 떨어지면, 2로 나눕니다.
- 1을 뺍니다.
정수 N이 주어졌을 때, 위와 같은 연산 세 개를 적절히 사용해서 1을 만들려고 합니다. 연산을 사용하는 횟수의 최솟값을 출력하고, 그 최적의 과정에 포함되어 있는 수들을 출력하는 프로그램을 작성하는 문제입니다.
- 입력: 첫째 줄에 1보다 크거나 같고, 10^6보다 작거나 같은 정수 N이 주어집니다.
- 출력: 첫째 줄에 연산을 하는 횟수의 최솟값을 출력합니다. 둘째 줄에는 N을 1로 만드는 방법에 포함되어 있는 수를 공백으로 구분해서 순서대로 출력합니다. (정답이 여러 가지인 경우에는 아무거나 출력합니다.)
링크: https://www.acmicpc.net/problem/12852
풀이: 1차원 배열 DP와 이전 경로 기록(pre)
기존의 '1로 만들기' 문제에서 최소 연산 횟수를 구하는 d 배열에 추가로, 역추적을 위한 pre 배열을 도입하여 해결하는 방식입니다.
- 상태 및 경로 배열 정의:
- d[i]: 숫자 i를 1로 만드는 데 필요한 최소 연산 횟수
- pre[i]: 숫자 i가 1이 되는 최적의 경로 상에서, i 바로 다음에 와야 할 숫자 (즉, 연산을 한 번 수행한 직후의 숫자)
- 상태 전이 (Bottom-Up):
- 숫자 2부터 N까지 순차적으로 반복문을 돕니다.
- 1을 빼는 경우 (기본값): 모든 숫자는 1을 뺄 수 있으므로, 우선 d[i] = d[i - 1] + 1로 설정하고 이전 숫자를 pre[i] = i - 1로 기록합니다.
- 2로 나누어 떨어지는 경우: 만약 i가 2의 배수이고, 2로 나누었을 때의 연산 횟수(d[i / 2] + 1)가 현재까지 기록된 횟수(d[i])보다 작다면, 값을 갱신하고 경로도 pre[i] = i / 2로 바꿉니다.
- 3으로 나누어 떨어지는 경우: 마찬가지로 3의 배수인지 검사하고 더 유리하다면 최솟값과 경로를 갱신합니다.
- 역추적 출력:
- 모든 계산이 끝난 후 d[n]을 통해 최솟값을 출력합니다.
- for문을 이용하여 n부터 시작해 pre[i]를 타고 계속해서 이전 숫자로 이동하며 출력합니다.
- 자바 배열의 기본 초기화 값인 0을 영리하게 활용하여, pre[1]의 값인 0에 도달할 때(i != 0) 반복문을 자연스럽게 종료합니다.
코드
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int n = Integer.parseInt(br.readLine());
// d: 최소 연산 횟수 저장, pre: 최적 경로 역추적
int[] d = new int[n + 1];
int[] pre = new int[n + 1];
d[1] = 0; // 1은 이미 1이므로 연산 횟수 0
// Bottom-Up 방식의 DP 탐색
for (int i = 2; i <= n; i++) {
// 1. 1을 빼는 연산
d[i] = d[i - 1] + 1;
pre[i] = i - 1;
// 2. 2로 나누는 연산 비교
if (i % 2 == 0 && d[i] > d[i / 2] + 1) {
d[i] = d[i / 2] + 1;
pre[i] = i / 2;
}
// 3. 3으로 나누는 연산 비교
if (i % 3 == 0 && d[i] > d[i / 3] + 1) {
d[i] = d[i / 3] + 1;
pre[i] = i / 3;
}
}
// 최솟값 출력
bw.write(d[n] + "\n");
// 역추적 배열을 활용하여 경로 출력
for (int i = n; i != 0; i = pre[i]) {
bw.write(i + " ");
}
bw.flush();
}
}
알고리즘 분류
다이나믹 프로그래밍 (Dynamic Programming), 그래프 탐색 (Graph Traversal), 역추적 (Backtracking)
'PS > B.O.J' 카테고리의 다른 글
| 4811번: 알약 (0) | 2026.04.22 |
|---|---|
| 1753번: 최단경로 (0) | 2026.04.21 |
| 9663번: N-Queen (0) | 2026.04.12 |
| 14497번: 주난의 난 (0) | 2026.04.12 |
| 9536번: 여우는 어떻게 울지? (1) | 2026.04.10 |