시간 제한
0.15초
메모리 제한
128MB
문제
정수 X에 사용할 수 있는 연산은 다음과 같이 세 가지 이다.
- X가 3으로 나누어 떨어지면, 3으로 나눈다.
- X가 2로 나누어 떨어지면, 2로 나눈다.
- 1을 뺀다.
정수 N이 주어졌을 때, 위와 같은 연산 세 개를 적절히 사용해서 1을 만들려고 한다. 연산을 사용하는 횟수의 최솟값을 출력하시오.
입력
첫째 줄에 1보다 크거나 같고, 106보다 작거나 같은 정수 N이 주어진다.
출력
첫째 줄에 연산을 하는 횟수의 최솟값을 출력한다.
예제 입력 1
2
예제 출력 1
1
예제 입력 2
10
예제 출력 2
3
힌트
10의 경우에 10 -> 9 -> 3 -> 1 로 3번 만에 만들 수 있다.
나의 풀이
- 처음엔 재귀로 풀었지만 메모리 초과가 발생했다.
- 왜 메모리 초과지? 라고 생각하다가 $DP[N-1]$을 계산하는 과정에서 get_dp 함수가 너무 많이 stack 돼서 메모리 초과가 발생함을 확인했다.
- https://www.acmicpc.net/board/view/21297
import sys
sys.setrecursionlimit(10**6)
n = int(input())
dp = [0] * (n + 1)
def get_dp(n):
if n == 1:
return 0
elif dp[n] != 0:
return dp[n]
else:
a, b = 1e9, 1e9
if n % 3 == 0:
a = get_dp(n // 3) + 1
if n % 2 == 0:
b = get_dp(n // 2) + 1
c = get_dp(n - 1) + 1
dp[n] = min(a, b, c)
return dp[n]
res = get_dp(n)
print(res)
- 반복문으로 다시 풀면 다음과 같다.
n = int(input())
dp = [0] * 1000001
for i in range(2, n + 1):
a, b = 1e9, 1e9
if i % 2 == 0:
a = dp[i // 2] + 1
if i % 3 == 0:
b = dp[i // 3] + 1
c = dp[i - 1] + 1
dp[i] = min(a, b, c)
print(dp[n])
다른 사람 풀이
- 재귀를 사용하려면 $DP[N-1]$로 재귀 함수가 실행되지 않아야 한다.
- 아래 코드의 경우 $DP[N//3]$과 $DP[N//2]$과정에 나머지 값을 더하여 해결했다.
- 좋은 아이디어!
import sys
read = sys.stdin.readline
N = int(read())
cache = {1: 0, 2: 1}
def dp(n):
if n in cache:
return cache[n]
# 핵심 코드
cnt = 1 + min(dp(n//3) + n%3, dp(n//2) + n%2)
cache[n] = cnt
return cnt
print(dp(N))