동빈나 강의 :https://www.youtube.com/watch?v=5Lu34WIx2Us
https://blog.naver.com/ndb796/221233570962
- 다이나믹 프로그래밍은 메모리를 적절히 사용하여 수행 시간 효율성을 비약적으로 향상시키는 방법
- 이미 계산된 결과(작은 문제)는 별도의 메모리 영역에 저장하여 다시 계산하지 않음
- 다이나믹 프로그래밍의 구현은 일반적으로 두 가지 방식(탑다운, 바텀업)으로 구성
일반적인 프로그래밍 분야에서의 동적(Dynamic)의 의미
- 프로그램이 실행되는 도중
자료구조에서 동적 할당(Dynamic Allocation)은 '프로그램이 실행되는 도중에 실행에 필요한 메모리를 할당하는 기법'
다이나믹 프로그래밍에서 다이나믹은 특별한 의미는 없음.
다이나믹 프로그맹의 조건
1. 최적 부분 구조 (Optimal Substructure)
- 큰 문제를 작은 무제로 나눌 수 있으며, 작은 문제의 답을 모아서 큰 문제를 해결 가능
2. 중복되는 부분 문제 (Overlapping Subproblem)
- 동일한 작은 문제를 반복적으로 해결해야 함
대표적인 동적 프로그래밍 문제
피보나치 수열
피보나치 수열은 다음과 같은 형태의 수열
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 ...
특정 번째의 수열은 앞 번째에 두 수의 합. 2 = 1+1 / 3 = 1+2
점화식
인접한 항들 사이의 관계식
피보나치 수열의 점화식:
An = An-1 + An-2 , A1 = 1, A2 = 1
실제 프로그램에서 재귀 함수와 점화식을 사용하면 해결 가능.
피보나치 수열 : 단순 재귀 소스코드
def fibo(x):
if x==1 or x==2:
return 1
return fibo(x-1) + fibo(x-2)
print(fibo(4))
>>>3
중복되는 부분 문제
다이나믹 프로그래밍의 사용조건을 만족하는지 확인
- 최적 부분 구조 : 큰 문제를 작은 문제로 나눌 수 있다.
- 중복되는 부분 문제: 동일한 작은 문제를 반복적으로 해결
따라서 피보나치 수열은 다이나믹 프로그래밍의 사용조건 만족
메모이제이션 ( Memoization ) | 탑다운 방식
한 번 계산한 결과를 메모리 공간에 메모하는 기법
- 같은 문제를 다시 호출하면 메모했던 결과를 그대로 가져옴
- 값을 기록해 놓는다는 점에서 캐싱(Caching)이라고도 함
탑다운 vs 바텀업
탑다운(메모이제이션) 방식은 하향식, (작은 문제들을 재귀적으로 해결해서 큰문제를 해결)
바텀업은 상향식 (아래 쪽에서부터 작은 문제를 하나씩 해결해나가며 먼저 해결한 문제들의 값을 활용해서 그 다음의 문제까지 차례대로 해결. 반복문)이라고도 함.
다이나믹 프로그래밍의 전형적인 형태는 보텀업 방식
- 결과 저장용 리스트는 DP 테이블이라고 부름
엄밀히 말하면 메모이제이션은 이전에 계산된 결과를 일시적으로 기록해 놓는 넓은 개념을 의미
피보나치 수열 : 탑다운 다이나믹 프로그래밍 소스코드
1. 탑다운
# 한 번 계산된 결과를 메모이제이션 하기 위한 리스트 초기화
dp = [0] * 100
# 피보나치 함수를 재귀함수로 구현
def fibo(x):
# 종료조건 (1 혹은 2일때 1을 반환)
if x == 1 or x == 2:
return 1
# 이미 계산한 적 있는 문제라면 그대로 반환
if dp[x] != 0:
return dp[x]
# 아직 계산하지 않은 문제라면 점화식에 따라서 피보나치 결과 반환
dp[x] = fibo(x-1) + fibo(x-2)
return dp[x]
print(fibo(99))
2. 바텀업
# 바텀업
# 한 번 계산된 결과를 메모이제이션 하기 위한 리스트 초기화
dp2 = [0] * 100
# 피보나치 함수를 재귀함수로 구현
dp2[1] = 1
dp2[2] = 1
n = 99
# 피보나치 수열 반복문으로 구현 (바텀업)
for i in range(3, n+1):
dp2[i] = dp2[i-1] + dp2[i-2]
print(dp2[n])
원래는 이와같이 단순재귀에서의 아주 많은 양의 연산을 줄일 수 있음
피보나치 수열 함수의 시간 복잡도는 O(N)
다이나믹 프로그래밍 vs 분할 정복
DP와 분할 정복 모두 최적 부분 구조를 가질 때 사용 할 수 있다.
- 큰 문제를 작은 문제로 나눌 수 있으며, 작은 문제의 답을 모아서 큰 문제를 해결할 수 있는 상황
DP와 분할 정복의 차이점은 부분 문제의 중복
- DP 문제에서는 각 부분 문제들이 서로 영향을 미치며 부분 문제가 중복됌
- 분할 정복에서는 동일한 부분 문제가 반복적으로 계산되지 않음
DP 문제에 접근하는 방법
주어진 문제가 DP 유형임을 파악하는 것이 중요
1. 가장 먼저 그리디, 구현, 완전 탐색등의 아이디어로 문제를 해결 할 수 있는지 검토
- 다른 알고리즘으로 풀이방법이 떠오르지 않거나, 너무 많은 시간복잡도가 소요될 것 같다면 DP를 고려
2. 일단 재귀 함수로 비효율적인 완전 탐색 프로그램을 작성한 뒤에 (탑다운) 작은 문제에서 구한 답이 큰 문제에서 그래도 사용될 수 있으면, 코드를 개선하는 방법으로 사용할 수 있다.
일반적인 코딩 테스트 수준에서는 기본 유형의 다이나믹 프로그래밍 문제가 출제되는 경우가 많다.
- 왜냐하면 DP문제가 출제될 시 그 문제에 맞는 점화식을 떠올리는 과정에서 많은 시간이 소요될 수 있기 때문.
'sw사관학교 정글 2기 > 알고리즘' 카테고리의 다른 글
알고리즘 공부 전략 + 유용한 링크 (0) | 2021.10.19 |
---|---|
그리디 알고리즘 (0) | 2021.08.30 |
Topological sort, 위상 정렬 (0) | 2021.08.25 |
그래프 탐색 알고리즘: DFS/BFS (0) | 2021.08.19 |
정렬 (0) | 2021.08.11 |
댓글