

DP가 이 DP는 아니겠죠...? ㅎㅎㅎㅎㅎ
흔히 Dynamic Programming(DP)라고도 부르는 동적 계획법은, 중복되는 하위 문제로 쪼갤 수 있는 문제를 해결할 때 활용합니다.
🤔 분할 정복에서도 큰 문제를 부분 문제로 분할하지 않았나요?
# 피보나치수열의 x번째 값 (단, x는 1부터 시작)
def fibo(x):
if x == 1 or x == 2:
return 1
return fibo(x - 1) + fibo(x - 2)
print(fibo(6)) # 8

fibo(6)를 작은 문제 fibo(5)와 fibo(4)로 나누고fibo(6)를 해결할 수 있음fibo(6)을 계산하는 과정에서 fibo(4)가 반복적으로 호출됨fibo(3), fibo(2), fibo(1)도 마찬가지🐥 일부 책이나 강의에선 상향식 방식만을 동적 계획법, 하향식 방식만을 메모이제이션이라고 엄격하게 구분하기도 합니다...만
# memo[i]에 fibo(i)의 반환값을 저장
# 아직 계산하지 못한 경우 None
memo = [None] * 100
# 피보나치수열의 i번째 값 (단, x는 1부터 시작)
def fibo(i):
# 첫번째, 두번째 값은 1
if i == 1 or i == 2:
return 1
if memo[i] is not None: # 이미 계산한 적 있는 경우
return memo[i]
# 아직 계산하지 않은 경우, 계산 후 결과를 memo 리스트에 저장
memo[i] = fibo(i - 1) + fibo(i - 2)
return memo[i]
print(fibo(99)) # 218922995834555169026
memo 리스트(DP 테이블)에 저장한 결과를 가져와서 시간이 단축됨fibo(6)을 구할 때, 아래 그림에서 노란색으로 칠한 함수만 실제로 호출됨
# memo[i]는 피보나치수열의 i번째 값 (단 i는 1부터 시작)
# 아직 계산하지 못한 경우 None
memo = [None] * 100
# memo[i]는 피보나치수열의 i번째 값
for i in range(1, 100):
# 첫번째, 두번째 값은 1
if i == 1 or i == 2:
memo[i] = 1
else:
memo[i] = memo[i - 1] + memo[i - 2]
print(memo[99]) # 218922995834555169026
fibo(6)을 구할 때, 수열 이전 항의 값은 1번씩만 계산됨
이때 계산된 값을 이후 계산에 활용
x | memo[x] |
|---|---|
1 | 1 |
2 | 1 |
3 | memo[2] + memo[1] = 2 |
4 | memo[3] + memo[2] = 3 |
5 | memo[4] + memo[3] = 5 |
6 | memo[5] + memo[4] = 8 |
🤔 **왜 두 코드에서 굳이 if i == 1 or i == 2 를 따로 조건문 처리 해 주나요? 그냥 memo[1] = 1, memo[2] = 1로 미리 저장하고 반복문 / 재귀호출을 하면 되는 거 아니에요?
N번째 수를 구할 때, memo 리스트는 N + 1의 길이로 만듭니다.memo는 0과 1 인덱스만 갖는 길이 2의 리스트가 됩니다.memo[2]가 존재하지 않아서 memo[2] = 1로 대입하려고 하면 IndexError가 뜹니다. 예외 처리라고 생각해주시면 됩니다.🤔 시간 복잡도도 동일한데, 그래서 뭘 써야 해요?
sys.setrecursionlimit(10**9)으로 높여줄 필요가 있음을 고려하세요. 그리고 가끔씩 재귀로는 시간제한 뜨는 문제들이 있어서, 재귀 필요없는 상향식을 선호하긴 합니다.N = int(input())
memo = [None] * (N + 1)
def fibo(x):
if x == 0:
return 0
elif x == 1:
return 1
if memo[x] is not None:
return memo[x]
memo[x] = fibo(x - 1) + fibo(x - 2)
return memo[x]
print(fibo(N))
벌써 진도 다빼놨네 ㅎㄷㄷ;;