티스토리 뷰
다이나믹 프로그래밍 (DP)
- 메모리를 적절히 사용하여 수행 시간 효율성을 비약적으로 향상시키는 방법
- 이미 계산된 결과(작은 문제)는 별도의 메모리 영역에 저장하여 다시 계산하지 않도록 한다.
- 다이나믹 프로그래밍의 구현은 일반적으로 두 가지 방식(Top-down, Bottom-up)으로 구성된다.
- 동적 계획법이라고도 부른다.
- 일반적으로 프로그래밍 분야에서 동적(Dynamic)이란 어떤 의미를 가질까?
- 자료구조에서 동적 할당(Dynamic Allocation)은 프로그램이 실행되는 도중에 실행에 필요한 메모리를 할당하는 기법을 의미한다.
- 반면에 다이나믹 프로그래밍에서 '다이나믹'은 별다른 의미 없이 사용된 단어이다.
- 다이나믹 프로그래밍은 문제가 다음의 조건을 만족할 때 사용할 수 있다.
- 최적 부분 구조(Optimal Substructure)
- 큰 문제를 작은 문제로 나눌 수 있으며 작은 문제의 답을 모아서 큰 문제를 해결할 수 있다.
- 중복되는 부분 문제(Overlapping Subproblem)
- 동일한 작은 문제를 반복적으로 해결해야 한다.
- 최적 부분 구조(Optimal Substructure)
피보나치 수열
피보나치 수열이란?
- DP를 활용할 수 있는 문제 중 대표적인 예제는 피보나치 수열이다.
- a1 = 1, a2 = 2일 때 이 전의 값을 더하여 다음의 값을 나타내는 수열
- 1, 1, 2, 3, 5, 8, 13, 21, 46, ...
def fibo(x):
if x == 1 or x == 2:
return 1
return fibo(x - 1) + fibo(x - 2)
print(fibo(4))
- 재귀함수는 무한루프를 돌지 않고 특정 조건에서 멈추도록 조건을 걸어준다.
- 피보나치의 수열은 첫번째 수와 두번째 수가 각각 1이기 때문에 이에 해당하는 조건을 걸어준다.
시간 복잡도 분석
- 단순 재귀 함수로 피보나치 수열을 해결하면 지수 시간 복잡도를 가지게 된다.
- 위의 그림과 같이 f(2)가 여러번 호출되는 것을 확인할 수 있다. (중복되는 부분 문제)
- 피보나치 수열의 시간 복잡도는 다음과 같다.
- 빅오 표기법: O(2^n)
- 빅오 표기법을 기준으로 f(30)을 계산하기 위해 약 10억가량의 연산을 수행해야 한다.피보나치 수열의 효율적인 해법: 다이나믹 프로그래밍
- 다이나믹 프로그래밍의 사용 조건을 만족하는지 확인한다.
- 최적 부분 구조: 큰 문제를 작은 부분으로 나눌 수 있는가?
- 작은 부분을 모아서 큰 문제를 해결할 수 있는가?
- 위의 그림을 예시로, f(4)를 구하기 위해서 f(2)와 f(3)의 합이라는 작은 문제로 나눠진다.
- 중복되는 부분 문제: 동일한 작은 문제를 반복적으로 해결할 수 있는가?
- 동일한 연산이 여러번 수행되는 것을 위의 그림에서 확인할 수 있다.
- 최적 부분 구조: 큰 문제를 작은 부분으로 나눌 수 있는가?
- 피보나치 수열은 DP 사용 조건을 만족한다.
Memoization
- DP의 두가지의 구현 방법 중 하향식(Top-Down) 방법.
- 한 번 계산된 결과를 메모리 공간에 메모하는 기법
- 같은 문제를 다시 호출하면 메모했던 결과를 그대로 가져온다.
- 값을 기록해 놓는다는 점에서 캐싱(Caching)이라고도 한다
- 이 경우 시간복잡도는 O(N)이 된다.
Top-Down(하향식) vs Bottom-Up(상향식)
- 탑다운 방식은 하향식이라고도 하며 보텀업 방식은 상향식이라고도 한다.
- 탑다운은 보통 재귀형식으로 구현
- 보텀업 방식은 보통 반복문으로 구현
- DP의 전형적인 형태는 보텀업 방식이다.
- 결과 저장용 리스트(배열)는 DP 테이블이라고 부른다.
- 엄밀히 말하자면 메모이제이션은 이전에 계산된 결과를 일시적으로 기록해 놓는 넓은 개념을 의미한다.
- 따라서 메모이제이션은 DP에 국한된 개념은 아니다.
- 한 번 계산된 결과를 담아 놓기만 하고 다이나믹 프로그래밍을 위해 활용하지 않을수도 있다.
탑다운 다이나믹 프로그래밍을 활용한 피보나치 수열 코드
d = [0] * 100 # 한 번 계산된 결과를 메모이제이션하기 위한 리스트
# 재귀함수로 구현
def fibo(x):
if x == 1 or x == 2: # 종료 조건
return 1
if d[x] != 0: # 이미 계산한 적 있는 문제라면 저장된 값을 사용
return d[x]
d[x] = fibo(x-1) + fibo(x-2) # 아직 계산한 적 없다면 점화식에 따라 피보나치 결과 반환
return d[x]
print(fibo(99))
보텀업 다이나믹 프로그래밍을 활용한 피보나치 수열 코드
d = [0] * 100
d[1] = 1
d[2] = 1
n = 99
for i in range(3, n + 1):
d[i] = d[i - 1] + d[i - 2]
print(d[n])
다이나믹 프로그래밍 문제에 접근하는 방법
- 주어진 문제가 다이나믹 프로그래밍 유형임을 파악하는 것이 중요하다.
- 그리디, 구현, 완전 탐색 등의 아이디어로 해결할 수 있는지 검토한다.
- 다른 알고리즘 풀이 방법이 떠오르지 않는다면 다이나믹 프로그래밍을 고려할 수 있다.
- 재귀 함수로 비효율적인 완전 탐색 프로그램을 작성한 뒤 (탑다운) 작은 문제에서 구한 답이 큰 문제에서 그대로 사용될 수 있으면, 코드를 개선하는 방법을 사용할 수 있다.
- 일반적인 코테 수준에서는 기본 유형의 다이나믹 프로그래밍 문제가 출제되는 경우가 많다.
DP 기초 문제 풀이
개미 전사
- 개미 전사는 부족한 식량을 충당하고자 메뚜기 마을의 식량창고를 몰래 공격하려고 한다. 메뚜기 마을에는 여러 개의 식량창고가 있는데 식량창고는 일직선으로 이어져 있다.
- 각 식량창고에는 정해진 수의 식량을 저장하고 있으며 개미 전사는 식량창고를 선택적으로 약탈하여 식량을 빼앗을 예정이다. 이때 메뚜기 정찰병들은 일직선상에 존재하는 식량창고 중에서 서로 인접한 식량창고가 공격받으면 바로 알아챌 수 있다.
- 따라서 개미 전사가 정찰병에게 들키지 않고 식량창고를 약탈하기 위해서는 최소한 한 칸 이상 떨어진 식량창고를 약탈해야 한다.
- 예를 들어 식량창고 4개가 다음과 같이 존재한다고 가정한다.
- {1, 3, 1, 5}
- 이때 개미 전사는 두 번째 식량창고와 네 번째 식량창고를 선택했을 때 최댓값인 총 8개의 식량을 빼앗을 수 있습니다. 개미 전사는 식량창고가 이렇게 일직선상일 때 최대한 많은 식량을 얻기를 원합니다.
- 개미 전사를 위해 식량창고 N개에 대한 정보가 주어졌을 때 얻을 수 있는 식량의 최댓값을 구하는 프로그램을 작성하라.
- 입력
- 첫째 줄에 식량창고의 개수 N (3 <= N <= 100)
- 둘째 줄에 공백을 기준으로 각 식량창고에 저장된 식량의 개수 K (0 <= K <= 1000)
- 입력
- 풀이
import sys
sys.stdin = open("DP-개미전사-input.txt", "rt")
n = int(sys.stdin.readline()) # 3 <= n <= 100
array = list(map(int, sys.stdin.readline().split())) # 0 <= k <= 1000
dp = [0] * 100
dp[0] = 0
dp[1] = max(array[0], array[1])
for i in range(2, n):
dp[i] = max(dp[i - 1], dp[i - 2] + array[i])
print(dp[n-1])
나동빈님의 이코테 유튜브 강의를 보고 정리한 글입니다.
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- kubernetes
- 네트워크
- 이코테
- elasticsaerch
- sqoop
- Espher
- kafka
- Algorithm
- HDFS
- 백준
- Hadoop
- DP
- Flutter
- OS
- 빅데이터
- DFS
- 파이썬
- mahout
- CSAPP
- BOJ
- heapq
- 프로그래머스
- Elasticsearch
- 빅데이터를지탱하는기술
- logstash
- oozie
- Python
- GROK
- CS
- cka
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
글 보관함