다이나믹 프로그래밍 문제에 접근하는 방법
- 주어진 문제가 다이나믹 프로그래밍 유형임을 파악하는 것이 중요
- 가장 먼저 그리디, 구현, 완전탐색 등의 아이디어로 해결할 수 있는지 검토
- 다른 알고리즘으로 풀이방법이 떠오르지 않으면 다이나믹 프로그래밍 고려
- 우선 재귀함수로 비효율적인 완전 탐색 프로그램을 작성한 후 Top-Down(작은 문제에서 구한 답이 큰 문제에 사용될 수 있음) 방식이 적용될 것 같으면 코드를 개선하는 식
- 점화식 떠올려보기
- 일반적인 코딩테스트 유형에서는 기본 유형의 다이나믹 프로그래밍 문제가 출제되는 경우가 많음
다이나믹 프로그래밍 문제1: 개미 전사


A(i): i번째까지의 식량창고가 존재할 때 털 수 있는 식량의 최댓값
K: 식량창고 리스트
개미전사 파이썬 코드
import sys
n = int(sys.stdin.readline())
k = list(map(int, sys.stdin.readline().split()))
# 점화식(Recurrence Relation)
# A(i) = max(Ai-1, k(1) + A(i-2))
dp = [0] * n
dp[0] = k[0]
dp[1] = max(dp[0], k[1])
for i in range(2, n):
dp[i] = max(dp[i - 1], k[i] + dp[i - 2])
다이나믹 프로그래밍 문제2: 1로 만들기


1로 만들기 파이썬 코드
# # X가 주어졌을 때
# # X//5 == 0 -> X//5
# # X//3 == 0 -> X//3
# # X//2 == 0 -> X//2
# # X - 1
# 네 가지 연산중 하나 골라서 실행
# bottom up
import sys
x = int(sys.stdin.readline())
dp = [0] * 30001
for i in range(2, x + 1):
# 4가지 연산으로 갈 수 있는 dp값을 리스트에 넣어주고 그 다음 최솟값이랑 + 1을 해줌
pre_dp = []
if i % 5 == 0:
pre_dp.append(dp[i//5])
if i % 3 == 0:
pre_dp.append(dp[i//3])
if i % 2 == 0:
pre_dp.append(dp[i//2])
pre_dp.append(dp[i - 1])
dp[i] = min(pre_dp) + 1
print(dp[x])
DP 문제3: 효율적인 화폐 구성


효율적인 화폐구성 파이썬 코드
# 효율적인 화폐구성
import sys
n, m = map(int, sys.stdin.readline().split())
arr = []
for i in range(n):
arr.append(int(sys.stdin.readline()))
d = [10001] * (m + 1)
d[0] = 0
for i in range(n):
for j in range(arr[i], m + 1):
if d[j - arr[i]] != 10001:
d[j] = min(d[j], d[j - arr[i]] + 1)
if d[m] == 10001:
print(-1)
else:
print(d[m])
이 문제는 먼저 화폐를 배열로 만든 후, 10001이라는 화폐의 최댓값보다 1이 큰 수가 m + 1개 들어가있는 DP 테이블을 생성해주어야 합니다. 그 다음 단위가 작은 화폐부터 구성할 수 있는 m 보다 작은 금액을 채워나가는 식으로 해결할 수 있습니다.
DP문제 4: 금광

이 문제의 경우 금광 분포로 2차원 배열을 생성 후 이를 토대로 새로운 배열의 각 칸에 누적된 최댓값을 입력해주는 방식으로 해결 가능하다.
금광 파이썬 코드
import sys
t = int(sys.stdin.readline())
for q in range(t):
n, m = map(int, sys.stdin.readline().split())
inp = list(map(int, sys.stdin.readline().split()))
table = [[0 for r in range(n)] for c in range(m)]
k = 0
for r in range(n):
for c in range(m):
table[c][r] = inp[k]
k += 1
d = table
for i in range(1, m):
for j in range(n):
if j == 0:
mid, lower = d[i - 1][j], d[i - 1][j + 1]
d[i][j] = max(mid, lower) + d[i][j]
elif j == n - 1:
upper, mid = d[i - 1][j - 1], d[i - 1][j]
d[i][j] = max(upper, mid) + d[i][j]
else:
upper, mid, lower = d[i - 1][j - 1], d[i - 1][j], d[i - 1][j + 1]
d[i][j] = max(upper, mid, lower) + d[i][j]
print(max(d[m - 1]))
참고
https://www.youtube.com/watch?v=5Lu34WIx2Us&list=PLRx0vPvlEmdAghTr5mXQxGpHjWqSz0dgC&index=6
'자료구조 & 알고리즘(Data Structure & Algorithm) > 알고리즘(Python)' 카테고리의 다른 글
동적계획법(Dynamic Programming) (0) | 2022.02.23 |
---|---|
순차 탐색 &이진 탐색 (0) | 2022.02.22 |
깊이우선탐색(DFS)/너비우선탐색(BFS) (0) | 2022.02.14 |
스택(Stack), 큐(Queue), 재귀(Recursion) (0) | 2022.02.14 |
구현(Implementation) (0) | 2021.08.03 |