https://www.acmicpc.net/problem/1463
1463번: 1로 만들기
첫째 줄에 1보다 크거나 같고, 106보다 작거나 같은 정수 N이 주어진다.
www.acmicpc.net
정수 X에 사용할 수 있는 연산은 다음과 같이 세 가지 이다.
- X가 3으로 나누어 떨어지면, 3으로 나눈다.
- X가 2로 나누어 떨어지면, 2로 나눈다.
- 1을 뺀다.
정수 N이 주어졌을 때, 위와 같은 연산 세 개를 적절히 사용해서 1을 만들려고 한다. 연산을 사용하는 횟수의 최솟값을 출력하시오.
입력
첫째 줄에 1보다 크거나 같고, \(10^6\)보다 작거나 같은 정수 N이 주어진다.
출력
첫째 줄에 연산을 하는 횟수의 최솟값을 출력한다.
예제 입력 1
2
예제 출력 1
1
예제 입력 2
10
예제 출력 2
3
시나리오
제시된 연산을 거쳐 정수 N을 1로 만들기 위해 필요한 최소 연산 횟수를 구하는 문제이다.
이 문제는 DP문제이다. DP의 원리는 이전 결과를 다음 결과에 이용하는 것이며 그렇기 때문에 점화식을 구하여 Top-Down 혹은 Bottom-up 구현법으로 푸는게 정석이다.
이 원리를 이번 문제에 적용해보자.
가장 작은 수 부터 1이 되게 하는데 필요한 횟수를 DP테이블에 저장해 가다가 어떤 정수가 2또는 3으로 나누어 떨어질 때 세가지 연산 중 어떤 연산을 해야 가장 적게 연산할지 알기 위해 DP테이블에 저장된 값(횟수)을 이용한다.
가령 x=10일 때, 10->9->3->1의 과정을 거쳐 1이 되는데
10은 -1 또는 2로 나눌 수 있기 때문에 cache[9]+1 과 cache[5]+1 중 더 작은 것을 cache[10]의 값으로 삼으면 되겠다.
cache[9]가 cache[5]보다 작기 때문에 전자를 cache[10]의 값으로 선택하게 되는데 이 때, 9는 -1 또는 3으로 나눌 수 있기 때문에 cache[8]+1과 cache[3]+1 중 더 작은 값을 cache[9]의 값으로 선택하게 되고 이 과정을 반복하는게 이번 문제의 풀이 방법이 되겠다.
다만 이번 풀이에서는 Bottom-up방식을 이용하기 때문에 cache[2]부터 cache[n]까지 차례로 구한다.
코드
#bottom-up
n = int(input())
#cache[k]==k를 1로 만들기 위한 연산 횟수
cache = [0] * (n + 1)
for i in range(2, n + 1):
#i-1의 횟수 + 1
cache[i] = cache[i - 1] + 1
#3으로 나누어 떨어질 때,
if not i % 3:
#i-1의 횟수 + 1 : i//3의 횟수 + 1 중 더 작은 값
cache[i] = min(cache[i], cache[i // 3] + 1)
#2와 3 모두를 약수로 갖는 정수일 경우 -1, 나누기 2, 나누기 3 세가지 연산 모두 비교해야 하므로 분기 하지않음
if not i % 2:
#i-1의 횟수 + 1 : i//2의 횟수 + 1 중 더 작은 값
cache[i] = min(cache[i], cache[i // 2] + 1)
print(cache[n])
다음 코드는 top-down으로 구현한 코드인데 제출하니 메모리 초과가 나왔다.
참고만 하도록 하자.
#top-down
import sys
n = int(input())
sys.setrecursionlimit(10 ** 6)
cache = [0] * (n + 1)
def make_one(num):
if cache[num]:
return cache[num]
if num < 2:
return cache[num]
if not num % 3:
cache[num] = min(make_one(num - 1) + 1, make_one(num // 3) + 1)
if not num % 2:
cache[num] = min(make_one(num - 1) + 1, make_one(num // 2) + 1)
if num % 3 and num % 2:
cache[num] = make_one(num - 1) + 1
return cache[num]
print(make_one(n))
'Algorithm > DP' 카테고리의 다른 글
| [Java] 프로그래머스 Lv2. 숫자 변환하기 (0) | 2023.04.08 |
|---|---|
| 백준 9465-스티커 (파이썬) (0) | 2022.10.01 |
| 백준 9095 - 1, 2, 3 더하기 (0) | 2022.09.21 |
| 백준 1912-연속합 (파이썬) (0) | 2022.09.19 |
| 백준 2579-계단 오르기 (파이썬) (0) | 2022.09.18 |