정수 X가 주어질 때 정수 X에 사용할 수 있는 연산은 다음과 같이 4가지이다.
- X가 5로 나누어떨어지면, 5로 나눈다.
- X가 3으로 나누어떨어지면, 3으로 나눈다.
- X가 2로 나누어떨어지면, 2로 나눈다.
- X에서 1을 뺀다.
정수 X가 주어졌을 때, 연산 4개를 적절히 사용해서 1을 만들려고 한다. 연산을 사용하는 횟수의 최솟값을 출력하시오.
x = int(input())
# 앞서 계산된 결과(횟수)를 저장
d = [0] * 30001
# 다이나믹 프로그래밍 진행 (보텀업)
for i in range(2, x+1):
# 현재의 수에서 1을 빼는 경우
# 1을 빼고 시작하는 이유 : 다음에 계산할 나누기에서 '1을 뺀 값'과 비교하여 횟수가 작은 것으로 교체될 것이기 때문에
d[i] = d[i-1] + 1
# 현재의 수가 2로 나누어 떨어지는 경우
if i % 2 == 0:
d[i] = min(d[i], d[i // 2] + 1) # 1을 더하는 이유 : d는 계산 횟수이기 때문, d[i]에 더하지 않는 이유는 위에서 1을 뺄 때 더해줬기 때문
# 현재의 수가 3로 나누어 떨어지는 경우
if i % 3 == 0:
d[i] = min(d[i], d[i // 3] + 1)
# 현재의 수가 5로 나누어 떨어지는 경우
if i % 5 == 0:
d[i] = min(d[i], d[i // 5] + 1)
print(d[x])
반복문을 통해 DP 테이블에 이전에 계산했던 값들을 저장하는 보텀업 방식
만약 x가 17이라면,
1. 1을 뺀 후 2로 나누기 -> 17-1=16, 16//2=8, 8//2=4, 4//2=2, 2//2=1 -> 총 5번
2. 1을 빼고 1을 또 빼고 5로 나누기 -> 17-1=16, 16-1=15, 15//5=3, 3//3=1 -> 4번
이렇게 빼기 연산을 먼저 할 것인지, 나누기를 먼저 할 것인지 주어지는 숫자마다 필요한 방식이 달라 코드로 구현하기 어렵다.
DP 테이블에 저장된 것들은 이미 최적해 이기 때문에 고민할 필요가 없다.