새소식

Computer Science/코딩테스트 문제 풀이

[백준] [파이썬] [DP] 1463번: 1로 만들기

  • -

문제집 추천, 이 문제집에 나온 유형들만 공부해도 코딩테스트는 거뜬: https://www.acmicpc.net/workbook/by/BaaaaaaaaaaarkingDog

 

1463번: 1로 만들기 문제보기

문제

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

  1. X가 3으로 나누어 떨어지면, 3으로 나눈다.
  2. X가 2로 나누어 떨어지면, 2로 나눈다.
  3. 1을 뺀다.

정수 N이 주어졌을 때, 위와 같은 연산 세 개를 적절히 사용해서 1을 만들려고 한다. 연산을 사용하는 횟수의 최솟값을 출력하시오.

입력

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

출력

첫째 줄에 연산을 하는 횟수의 최솟값을 출력한다.

예제 입력 1

2

예제 출력 1

1

예제 입력 2

10

예제 출력 2

3


DP중
Top-Down: 제일 작은 인덱스의 수 부터 목표하는 값으로 향하는것
Buttom-Up: 제일 큰 인덱스의 수 부터 재귀로 제일 작은 인덱스로 향하는 것

이번 문제는 1을 빼는 경우, 2로 나누는 경우, 3으로 나누는 경우, 이렇게 모든 경우의 수 중 최소값을 찾아내야 하기 때문에 모든 가능성을 두고 그 안에 최소값을 찾는다. 따라서 중복해 계산되는 값을 저장하며 진행하기 위해 메모이제이션 방법인 Top-Down 방식으로 문제를 푼다.

 

예를 들어 설명해보자. 10이 주어졌을때, 10 -(-1)-> 9 -(%3)-> 3 -(%3)-> 1

3번만에 1이 된다. 이것을 dp 테이블에 각 수까지 경우의 수를 저장하면

 

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 에서

1) 1에서 1이 되는데 0 [1]=1
2) 2에서 2를 나누는 연산을 1번 하므로 1 [2]=1
3) 3에서 3을 나누는 연산을 1번 하므로 1 [3]=1
4) 4에서 3)에서 1번 연산을 수행했으므로 4에서 1을 빼고 3)을 수행하므로 2 (-1)+[3]=2
5) 5에서 4)에서 2번 연산을 수행했으므로 5에서 1을 빼고 4)를 수행하므로 3 (-1)+[4]=3
6) 6에서 3을 나누면 3이되고 3)을 수행하므로 2 (%3)+[3]=2
7) 7에서 -1을 하고 6)을 수행하므로 3 (-1)+[6]=3
8) 8에서 2를 나누고 4)를 수행하므로 3 (%2)+[4]=3
9) 9에서 3을 나누고 3)을 수행하므로 2 (%3)+[3]=2
10) 10에서 -1을 하고 9)를 수행하므로 3 (-1)+[9]=3

위와 같이 생각하면 되겠다.

 

 


 

정답

 

import sys 
sys.stdin=open('input.txt','r')

if __name__=="__main__":
    N=int(input())
    dp=[0]*(N+1)            # 10이 주어지면 1부터 10을 보면서 저장할 테이블을 만든다
    # dp[1]=0
    for x in range(2,N+1):  # x=2일때, x=3일때,...x=10일때
        dp[x]=dp[x-1]+1                     # 1을 빼는 연산
        if x%3==0:                          # 3으로 나눠 떨어지면 
            dp[x]=min(dp[x], dp[x//3]+1)    # 1을 빼는 연산과 3을 나누는 연산 중 뭐가 덜 드는지 
        if x%2==0:                          # 2로 나눠 떨어지면 
            dp[x]=min(dp[x], dp[x//2]+1)    # 1을 빼는 연간과 3을 나누는 연산과 2를 나누는 연산 중 뭐가 덜 드는지
        # 2랑 3랑 모두 나눠질 수 있으므로 if elif는 사용하지 않는다. 예를들어 6
    print(dp[N])

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.