きっかけ:ABC219Dと次の記事.
貰う DP と配る DP、メモ化再帰、個数制限なしナップサック問題 - Qiita
DP
考え方
答えを$f(N)$とすると,$x = 0,1,...,N-1$に対して$f(x)$がわかっていれば$f(N)$が計算できる.よって,DPで求められる.具体的には,
\begin{aligned}
f(N)
=\min \{ f(N - 1) + 1, f(N - 6^{i}) + 1, f(N - 9^{i}) + 1 \}
\end{aligned}
である(ただし,$i$は可能な範囲をすべて動く).f(N)
=\min \{ f(N - 1) + 1, f(N - 6^{i}) + 1, f(N - 9^{i}) + 1 \}
\end{aligned}
以下,$f(i)$をdp[i]
で表す.
貰うDP
dp[i]
に遷移させるように更新する.
N = int(input()) dp = [N] * (N + 1) dp[0] = 0 for i in range(1, N + 1): for j in [6, 9]: k = j while k <= i: dp[i] = min(dp[i], dp[i - k] + 1) k *= j dp[i] = min(dp[i], dp[i - 1] + 1) print(dp[N])
配るDP
dp[i]
から遷移するように更新する.
N = int(input()) dp = [N] * (N + 1) dp[0] = 0 for i in range(N): for j in [6, 9]: k = j while i + k <= N: dp[i + k] = min(dp[i + k], dp[i] + 1) k *= j if i + 1 <= N: dp[i + 1] = min(dp[i + 1], dp[i] + 1) print(dp[N])
メモ化再帰
from functools import lru_cache N = int(input()) @lru_cache(maxsize = None) def f(x): if x == 0: return 0 p, q = 1, 1 while x - 9 ** p >= 0: p += 1 while x - 6 ** q >= 0: q += 1 tmp1 = f(x - 9 ** (p - 1)) + 1 tmp2 = f(x - 6 ** (q - 1)) + 1 return min(tmp1, tmp2) print(f(N))