1463번: 1로 만들기

첫째 줄에 1보다 크거나 같고, 106보다 작거나 같은 정수 N이 주어진다.

www.acmicpc.net

시간 제한

0.15초

메모리 제한

128MB

문제

정수 X에 사용할 수 있는 연산은 다음과 같이 세 가지 이다.

  1. X가 3으로 나누어 떨어지면, 3으로 나눈다.
  2. X가 2로 나누어 떨어지면, 2로 나눈다.
  3. 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))
 

백준 1463 파이썬 - 1로 만들기 - 동적 계획법

백준 1463 파이썬 https://www.acmicpc.net/problem/1463 1463번: 1로 만들기 첫째 줄에 1보다 크거나 같고, 106보다 작거나 같은 정수 N이 주어진다. www.acmicpc.net 정수 X가 주어졌을 때 3으로 나누어 떨어지..

myjamong.tistory.com