Algorithm/유형별 문제 풀기
[다이나믹 프로그래밍] 문제 이름 : 1로 만들기
sw_develop
2021. 11. 24. 12:06
문제 설명
정수 X가 주어질 때 정수 X에 사용할 수 있는 연산은 다음과 같이 4가지 이다.
1. X가 5로 나누어떨어지면, 5로 나눔
2. X가 2로 나누어떨어지면, 2로 나눔
3. X가 3으로 나누어떨어지면, 3으로 나눔
4. X에서 1을 뺌
정수 X가 주어졌을 때, 위의 연산 4개를 적절히 사용해 1을 만들려고 한다. 연산을 사용하는 횟수의 최소값을 구하시오.
사용 개념
다이나믹 프로그래밍, 보텀업 방식
문제 해결 아이디어
모든 연산 가능 경우에 대해 생각해봐야 할 것 같은데 너무 많은 것 아니야..? → 맞아! 경우의 수로 모든 경우에 대해 봐야되는거 맞는데 다이나믹 프로그래밍을 사용해서 빠르게 구하는거지! 어차피 최소 연산 횟수 구하는 것이니까!
1. 함수 호출 과정 도식화하기
→ 모든 경우의 수에 대해 고려할 때 동일한 함수들이 여러 번 호출됨을 알 수 있음
→ 이때 동일한 함수에서 구하는 값들은 모두 동일해야 하므로 다이나믹 프로그래밍 적용 가능
** 다이나믹 프로그래밍을 사용하기 위한 조건
https://fordevelop.tistory.com/53#다이나믹-프로그래밍을-사용하기-위한-조건
2. 점화식 표현
→ aᵢ : i 값을 1로 만들기 위해 필요한 최소 연산 횟수
3. 점화식을 바탕으로 보텀업(Bottom-Up) 다이나믹 프로그래밍 코드 작성
코드
import java.util.Scanner;
public class Main {
public static int[] result = new int[30001]; // 배열의 원소 값 : 해당 값을 1로 만들기 위해 필요한 연산 횟수의 최소값, 한 번 계산된 결과를 배열에 저장해둠
public static void main(String[] args) {
Scanner kbd = new Scanner(System.in);
int val = kbd.nextInt(); // 최대 : 30,000
// 다이나믹 프로그래밍 진행(보텀업)
for(int i = 2; i <= val; i++) {
// 연산1. 현재의 수 - 1
result[i] = result[i-1] + 1;
// 연산2. 현재의 수가 2로 나누어 떨어지는 경우
if (i % 2 == 0)
result[i] = Math.min(result[i], result[i/2] + 1);
// 연산3. 현재의 수가 3으로 나누어 떨어지는 경우
if (i % 3 == 0)
result[i] = Math.min(result[i], result[i/3] + 1);
// 연산4. 현재의 수가 5로 나누어 떨어지는 경우
if (i % 5 == 0)
result[i] = Math.min(result[i], result[i/5] + 1);
}
// 연산 하는 횟수의 최솟값 구하기
System.out.println(result[val]);
}
}
→ 구하는 것 : 사용자가 입력한 값을 1로 만들기 위해 필요한 연산 횟수의 최소값 (= result[x] 값)
→ 배열의 원소 값 : 해당 값을 1로 만들기 위해 필요한 연산 횟수의 최소값
→ 보텀업 방식으로 작은 값부터 차례대로 연산 횟수의 최소값을 구함