DP의 큰 예로 피보나치 수열을 확인해 볼 수 있다.
쉽게 생각해 본다면 분할정복과 비슷하고, 재귀함수와도 비슷하다. 재귀와 분할과의 차이점이 있다면, 함수를 불러오는것과, 함수값! 을 가져오는것의 차이가 아니까? 생각한다. 연산을 위해 반복해서 알고리즘을 호출한 후 다음 값을 집어넣어 결과값을 도출하는것과, 미리 계산된 결과값을 dp 테이블에 집어넣어 필요할때마다 해당 인덱스의 결과값을 가져오게 되는것. 두가지의 차이점은 당연히 시간, 메모리가 될것이다.
피보나치에 대한 dp 식은 아래 코드에 첨부할 예정!
그럼 문제에는 어떻게 적용할까? DP는 생각과 아이디어가 대부분이다. 뻗어나가기도 쉽고, 문제도 다양하고, 사용할수 있는 방법또한 다양하다. 즉, 정해진 방법이 있는게 아닌, 앞서서 정리한 개념들을 토대로 문제에 적합하게 적용해 내야 한다. 그렇기에 많은 문제들을 접해보며 활용해 보는게 dp학습에 큰 도움이 될거라 생각한다.
큰 틀로 문제를 분석해본다면,
DP문제의 해결은 대부분 DP식, 즉 점화식을 잘 세우는 것이 중요하다. 주어진 문제가 DP유형이 맞는지 확인하고, 최종적으로 구할 큰 문제가 뭔지 확인해야 한다.
#https://www.acmicpc.net/problem/2748
#피보나치 수 2
#2748
import sys
input = sys.stdin.readline
n = int(input())
dp = [0] * 91
def fun(n):
if n == 0:
dp[0] = 0
if n == 1:
dp[1] = 1
if n >= 2:
dp[0] = 0
dp[1] = 1
for i in range(2, n+1):
dp[i] = dp[i-1] + dp[i-2]
return dp
result = fun(n)
answer = result[n]
print(answer)
#https://www.acmicpc.net/problem/9084
#동전
#9084
t = int(input())
def fun(n, coin, m):
for i in range(n):
for j in range(m+1):
if j == coin[i]:
dp[j] += 1
elif j > coin[i]:
dp[j] += dp[j-coin[i]]
return dp
# result = fun(n, coin, m)
# answer = result[m]
# print(answer)
for _ in range(t):
# n = 동전의 가지수 / coin = 각 동전의 개수 / m = 만들어야 하는 금액
n = int(input())
coin = list(map(int, input().split()))
m = int(input())
dp = [0] * (m+1)
result = []
result = fun(n, coin, m)
print(result[m])