알고리즘/Dynamic Programming

Removing Digits

Algorithmus 2022. 5. 4. 08:08

https://cses.fi/problemset/result/3889109/

 

https://cses.fi/problemset/result/3889109/

 

cses.fi

이 문제는 주어진 숫자 n이 가진 각 자리의 수 중에서 하나씩 빼어서 0이 되는 최소의 연산 수를 구하는 것이다. 즉, 최적해는 2720181090.으로 총 5번의 연산이 최소한 필요하다. 여기서 dp[x]를 x라는 수를 0으로 만들기 위한 최소의 연산 수라고 정의하자.

우선, 27의 자리의 수는 2, 7이다. 그러므로 dp[27]을 구하려면, dp[25], dp[20] 으로 가는 2가지 경우가 있다. 그리디로 풀자면 dp[20]으로 무조건 가면 되지만, dp로 풀자면 두 경우를 모두 계산해서 비교해봐야 한다. 단, 주의할 것은, 각 상태 사이의 관계식이다. 각 자리 수를 d라 할 때, 모든 자리의 수 d에 대해 loop을 돌려 최소의 대안을 찾기 위해, 직전 loop 에서 연산된 내용인 dp[x] (첫 loop이었다면, 초기값인 INF) 와 지금 loop에서의 대안을 비교한다.

dp[x] = min(dp[x], dp[x - d] + 1)

이 된다. dp[20]에서 dp[27]로 올 때 연산 수가 1번 더해져야 하기 때문이다.

코드는 다음과 같다.

n = int(input())

dp = [0] + [float('inf')] * n
for x in range(1, n + 1):
    num, digits = x, []
    while num:
        digits.append(num % 10)
        num //= 10
    for d in digits:
        if x - d >= 0:
            dp[x] = min(dp[x], dp[x - d] + 1)

print(dp[n])
반응형

'알고리즘 > Dynamic Programming' 카테고리의 다른 글

LIS (longest increasing subsequence)  (0) 2022.05.27
0/1 Knapsack 세가지 자료구조  (0) 2022.05.22
Coin Combinations II  (0) 2022.05.03
Coin Combinations I  (0) 2022.05.01
DP 실수 모음  (0) 2022.04.29