다이나믹 프로그래밍(Dynamic Programming)
- 프로그래밍과 연관지어 생각하고, 완성한 코드를 분석하는 습관은 중요하다.
- 문제를 해결하기 위해 핵심적으로 다뤄지는 다이나믹 프로그래밍과 그리디(Greedy)에 대해 알아본다.
동적 계획법
- 동적 계획법은 동적 알고리즘, 동적 프로그래밍, 다이나믹 프로그래밍 등 다양한 용어로 사용되는데, 보편적 의미는 ‘문제의 일부분을 풀고 그 결과를 재활용하는 방법’이다.
- 하나의 문제를 중복되는 서브 문제로 나누어 푸는 방법이다.
- 분할 정복(Divide and Conquer)과 유사한 개념이다.
- 새로운 알고리즘이나 방법론을 알게 되었을 때 기존에 완성한 간결한 코드를 분석하고 이해하는 것이 좋다.
- DP는 알고리즘에서 재귀와 함께 사용되기 때문에 코드를 분석하면서 흐름을 이해해야 한다.
동적 계획법을 사용하게 되는 상황
- 이진 검색
- 최단 경로 알고리즘
- 최적화 문제
- 외판원 문제
동적 계획법과 분할 정복의 차이
- 동적 계획법에는 분할 정복에 아래 개념이 추가된다.
- 반복되는 서브 문제(Overlapping Subproblems)
- 메인과 서브 문제를 같은 방법으로 해결할 수 있어야 한다.(문제 해결 관점)
- 최적 부분 구조(Optimal Substructure)
- 메인 문제 해결 방법을 서브 문제에서 구하여 재사용하는 구조여야 한다.(문제의 구조 관점)
- 동적 계획법은 최적 부분 구조로 구성된 중복된 서브 문제를 분할 정복으로 해결한다.
동적 계획법의 두가지 방법론
메모이제이션(하향식 방법)
- 메인 문제를 분할하면서 해결하는 방법이다.
태뷸레이션(상향식 방법)
- 가장 작은 문제를 먼저 해결하고 최종적으로 메인 문제를 해결하는 방법이다.
피보나치 수열 개념 적용 소스 코드
메모이제이션
1 |
|
태뷸레이션
1 |
|
그리디(Greedy)
탐욕 알고리즘
- DP가 중복되는 서브 문제를 다뤘다면, 그리디는 중복되지 않는 서부 문제를 다룬다.
- 탐욕 알고리즘은 발견법(heuristic method)의 방법 중 하나이다.
- 발견법: 최선, 최적의 답을 찾기보다 주어진 상황을 한단계씩 빠른 시간 내에 해결하기 위해 사용하는 방법론이다.
- 역추적(backtracking)과 같이 알고리즘 수행 시간이 많이 걸릴 때 사용하는 방법이다.
- 탐욕법은 이전의 선택으로 돌아가는 역추적과는 반대개념으로 다른 문제들과 독립적이다.
- 어떠한 문제가 있을 때 단순 무식하게, 탐욕적으로 문제를 푸는 알고리즘이다.
- 현재 상황에서 지금 당장 좋은 것만 고르는 방법을 의미한다.
실제 상황 예시
여행 짐 싸기
- 여행 배낭에 물건을 정해진 시간 내에 담으려는 경우, 우선 순위가 높은 순서대로 물건을 담을 때 한번 배낭에 담은 물건은 다시 빼지 않는다.
여행 경로 짜기
- 도시가 많아질수록, 도시를 방문할 수 있는 가짓수가 많아진다.
- 알고리즘 연산 비용도 함께 증가한다. 이런 상황에서 탐욕 알고리즘을 활용한다.
- 방문하지 않은 도시 중 가장 가까운 도시로 간다.
- 모든 도시를 방문할 때까지 반복한다.
전력망 연결
- 발전소 한 개로 여러 마을에 전력을 공급하는 경우, 최소 비용을 들여 모든 마을에 전력을 공급하려면,
- 전력이 공급되지 않은 마을과 공급되는 마을의 사이가 가장 가까운 것을 골라, 두 마을을 연결한다.
- 모든 마을에 전력이 공급될 때까지 반복한다.
파이썬 예제
1 |
|
DP와 Greedy
- 최적 부분 구조 문제를 푼다는 점에서 비교된다.
DP
- 문제를 작은 단위로 분할하여 해결한 후, 해결된 중복 문제들의 결과를 기반으로 전체 문제를 해결한다.
Greedy
- 각 단계마다 최적해를 찾는 문제로 접근한다.
- 해결해야 할 전체 문제의 갯수를 줄이기 위해 개별적으로 문제를 해결해나가는 선택을 한다.