1. 문제 설명
https://www.acmicpc.net/problem/9184


2. 코드
import sys
input = sys.stdin.readline
dp = [[[0] * 21 for _ in range(21)] for _ in range(21)]
vis = [[[False] * 21 for _ in range(21)] for _ in range(21)]
def w(a: int, b: int, c: int) -> int:
# base
if a <= 0 or b <= 0 or c <= 0:
return 1
# clamp
if a > 20 or b > 20 or c > 20:
return w(20, 20, 20)
if vis[a][b][c]:
return dp[a][b][c]
vis[a][b][c] = True
if a < b and b < c:
dp[a][b][c] = w(a, b, c - 1) + w(a, b - 1, c - 1) - w(a, b - 1, c)
else:
dp[a][b][c] = (
w(a - 1, b, c)
+ w(a - 1, b - 1, c)
+ w(a - 1, b, c - 1)
- w(a - 1, b - 1, c - 1)
)
return dp[a][b][c]
out = []
while True:
a, b, c = map(int, input().split())
if a == -1 and b == -1 and c == -1:
break
out.append(f"w({a}, {b}, {c}) = {w(a, b, c)}")
print("\n".join(out))
3. 풀이 과정
주어진 재귀함수는 한번에 재귀로 4번을 더 해야 하기 때문에 같은 값을 수백번 다시 계산해야 할 수도 있다.
20을 넘어가면 무조건 w(20,20,20)으로 귀결되고 0 이하면 바로 1로 간다.
따라서 0 부터 20까지만 계산하면 된다.
동적 프로그래밍(DP) 테이블을 활용하면 한 번 계산한 값은 다시 계산할 필요가 없다.
따라서 계산한 적이 있는지를 체크하고 없을 때 계산하는 방식으로 변화를 준다.
if 이미 계산한 적 있는지:
바로 반환
else:
계산하고 저장
다음 기법을 메모이제이션(Memoization) 또는 Top-Down Dynamic Programming이라 한다.
풀이 설계는 다음과 같이 했다.
w(a,b,c)의 값은 dp[a][b][c]에 하였다.
이미 계산했는지 확인은 vis[a][b][c]에 논리값으로 저장하도록 하였다.
0부터 20까지 범위를 벗어난 경우를 정의하고,
vis 함수에서 True이면 저장된 값을 꺼내고,
False이면 계산한다.
출력값을을 out에 저장해두고,
a,b,c가 -1이 될 때까지 재귀를 진행한다.
4. 자투리 개념
- 동적 프로그래밍(Dynamic Programming)
- 이미 계산한 값을 버리지 않고 배열에 저장하여 필요한 순간 바로 꺼내 쓰는 방식
- '작은 문제의 해답을 저장해두고, 그것을 이용해 큰 문제를 해결한다.'
반응형
'Baekjoon(Python) > 단계별로 풀어보기(Python)' 카테고리의 다른 글
| [백준][21단계 동적 계획법 1] 1904번 /01타일 (파이썬/Python) (0) | 2026.01.30 |
|---|---|
| [백준][21단계 동적 계획법 1] 24416번 /알고리즘 수업 - 피보나치 수 1 (파이썬/Python) (0) | 2025.11.24 |
| [백준][20단계 백트래킹] 14889번 /스타트와 링크 (파이썬/Python) (0) | 2025.11.17 |
| [백준][20단계 백트래킹] 14888번 /연산자 끼워넣기 (파이썬/Python) (0) | 2025.11.13 |
| [백준][20단계 백트래킹] 2580번 /스도쿠 (파이썬/Python) (0) | 2025.11.03 |