동적 프로그래밍이란 무엇일까요?
동적 프로그래밍은 수학자이자 경제학자인 리처드 벨먼에 의해 고안된 방법론입니다.
벨먼은 복잡한 최적화 문제, 즉 주어진 선택지들 중에서 최적의 해결책을 찾아야 하는 문제들을 해결하기 위한 효율적인 접근법을 모색했습니다.
대표적인 최적화 문제 중 하나로 ‘외판원 문제’를 들 수 있습니다. 외판원 문제는 여러 도시들을 모두 방문하고 출발점으로 돌아오는 가장 짧은 경로를 찾는 문제입니다.
이러한 문제들에 대한 벨먼의 해결 전략은 전체 문제를 더 작은 하위 문제들로 분할하고, 가장 작은 문제부터 차례대로 해결해 나가는 것이었습니다. 각 하위 문제의 결과는 저장되어 더 큰 문제를 해결할 때 재사용되었습니다. 이것이 동적 프로그래밍의 핵심 아이디어입니다.
동적 프로그래밍의 개념
동적 프로그래밍은 최적화 문제 해결에 있어서, 문제를 작은 하위 문제들로 나누어 해결하고, 각 하위 문제의 해답을 한 번만 계산하여 저장해 둔 후, 더 큰 문제 해결에 재활용하는 방식입니다. 이는 가장 작은 하위 문제부터 시작하여, 점진적으로 큰 문제로 확장해 나가는 접근법입니다.
동적 프로그래밍의 작동 원리
동적 프로그래밍을 활용한 문제 해결은 다음과 같은 단계로 진행됩니다.
- 하위 문제 정의: 주어진 큰 문제를 해결하기 쉬운 작은 하위 문제들로 나눕니다.
- 하위 문제 해결: 식별된 각 하위 문제를 재귀 또는 반복을 통해 해결합니다.
- 해결 결과 저장: 하위 문제의 해답을 저장하여 이후에 재사용할 수 있도록 합니다.
- 최종 해결책 구성: 저장된 하위 문제 해답들을 바탕으로 원래 문제에 대한 최종 해답을 도출합니다.
이 과정을 더 잘 이해하기 위해, 6번째 피보나치 수인 F(6)를 계산하는 과정을 예시로 살펴보겠습니다.
먼저, 하위 문제들을 정의합니다. 피보나치 수열의 정의에 따라:
F(n) = n > 1 일 때 F(n-1) + F(n-2)
이를 통해 다음과 같은 관계식을 얻을 수 있습니다:
F(6) = F(5) + F(4)
F(5) = F(4) + F(3)
F(4) = F(3) + F(2)
F(3) = F(2) + F(1)
F(2) = F(1) + F(0)
F(1) = 1
F(0) = 0
두 번째 단계는 재귀 함수 또는 반복적인 과정을 활용하여 각 하위 문제를 해결하는 것입니다. 작은 하위 문제의 결과를 재사용하면서 가장 작은 문제부터 가장 큰 문제까지 순차적으로 해결합니다. 이 과정을 통해 다음과 같은 결과를 얻습니다.
F(0) = 0
F(1) = 1
F(2) = F(1) + F(0) = 1 + 0 = 1
F(3) = F(2) + F(1) = 1 + 1 = 2
F(4) = F(3) + F(2) = 2 + 1 = 3
F(5) = F(4) + F(3) = 3 + 2 = 5
F(6) = F(5) + F(4) = 5 + 3 = 8
각 하위 문제를 해결할 때마다, 그 결과를 배열이나 테이블에 저장함으로써, 더 큰 하위 문제 해결에 재사용할 수 있습니다.
모든 하위 문제가 해결되면, 저장된 결과들을 이용하여 원래 문제의 해결책을 도출합니다.
위의 예시에서는, 원래 문제의 해답은 가장 큰 문제에서 식별된 하위 문제인 F(5)와 F(4)의 결과를 더하여 얻어지는 6번째 피보나치 수 8입니다.
동적 프로그래밍 활용 분야와 이유
동적 프로그래밍은 큰 문제가 작은 하위 문제들로 분할될 수 있고, 이러한 하위 문제들의 해결책이 더 큰 문제 해결에 활용될 수 있는 경우에 유용하게 활용됩니다.
동적 프로그래밍은 컴퓨터 과학, 경제학, 수학, 공학 등 다양한 분야에서 활용됩니다. 컴퓨터 과학에서는 시퀀스, 그래프, 정수 값 관련 문제 해결, 경쟁적 프로그래밍 등에 활용됩니다. 경제학에서는 재정, 생산, 자원 배분 등의 최적화 문제 해결에 사용됩니다. 수학 분야에서는 게임 이론, 통계, 확률 등 최적화 문제 해결에 동적 프로그래밍이 활용됩니다. 공학에서는 자원 할당, 스케줄링, 제조, 통신, 제어 시스템 등의 문제 해결에 사용됩니다.
동적 프로그래밍을 통한 최적화 문제 해결은 다양한 이점을 제공합니다.
- 효율성: 동적 프로그래밍은 중복 계산을 피하므로 다른 최적화 알고리즘보다 효율적입니다.
- 대규모 문제 해결: 문제를 하위 문제로 분할하여 복잡성을 줄이므로, 다른 방법으로 해결하기 어려운 큰 최적화 문제에 효과적입니다.
- 최적의 솔루션 보장: 하위 문제와 목표가 정확하게 정의된 경우, 최적의 해결책을 찾을 수 있습니다.
- 단순성: 특히 문제를 특정 순서로 정의할 수 있는 경우, 구현과 이해가 비교적 쉽습니다.
- 확장성: 추가적인 하위 문제나 목표 수정을 통해 더 복잡한 문제를 해결하도록 쉽게 확장할 수 있습니다.
동적 프로그래밍은 최적화 문제 해결에 있어, 효율성을 보장하는 매우 유용한 도구입니다.
동적 프로그래밍의 접근 방식
동적 프로그래밍에서는 주로 하향식 접근 방식과 상향식 접근 방식, 두 가지 방법을 사용하여 최적화 문제를 해결합니다.
하향식 접근법
이 접근 방식은 ‘메모이제이션’이라고도 불립니다. 메모이제이션은 함수 호출 결과를 캐시에 저장하여, 다음에 동일한 계산이 필요할 때 캐시된 결과를 활용함으로써 프로그램의 실행 속도를 높이는 최적화 기법입니다.
하향식 접근법은 재귀 호출과 캐싱을 결합합니다. 재귀 함수는 자기 자신을 다시 호출하여 문제를 더 작은 하위 문제로 나누어 해결합니다. 각 하위 문제의 해결 결과는 캐시에 저장되어, 동일한 하위 문제가 다시 발생했을 때 재사용됩니다.
하향식 접근법은 이해하고 구현하기 쉽고, 각 하위 문제를 한 번만 해결합니다. 하지만 재귀 호출로 인해 메모리 사용량이 커질 수 있으며, 이는 스택 오버플로 오류를 유발할 수 있습니다.
상향식 접근법
상향식 접근법은 ‘표 작성’ 방식이라고도 하며, 재귀 호출 대신 반복문을 사용하여 스택 오버플로 오류를 방지합니다.
이 방식에서는 큰 문제를 작은 하위 문제로 나누고, 하위 문제의 해답을 이용하여 더 큰 문제를 해결합니다.
가장 작은 하위 문제부터 시작하여 가장 큰 문제까지 순차적으로 해결하고, 각 하위 문제의 결과는 행렬, 배열, 혹은 테이블에 저장합니다. 이를 통해 저장된 결과는 의존 관계에 있는 더 큰 문제 해결에 활용됩니다. 이후, 저장된 값을 사용하여 최종적으로 원래 문제의 해결책을 도출합니다.
상향식 접근법은 재귀를 사용하지 않기 때문에, 메모리와 시간 사용 효율성이 높다는 장점이 있습니다.
동적 프로그래밍으로 해결 가능한 문제 예시
동적 프로그래밍을 활용하여 해결할 수 있는 몇 가지 프로그래밍 문제들을 소개합니다.
#1. 배낭 문제
출처: 위키백과
배낭 문제는 배낭의 용량과 각 물품의 가치 및 무게가 주어졌을 때, 배낭에 담을 수 있는 물품들의 가치 합이 최대가 되도록 물품을 선택하는 문제입니다.
예를 들어, 15kg 용량의 배낭을 가지고 하이킹을 간다고 가정해 봅시다. 가져갈 수 있는 물품과 각 물품의 가치 및 무게는 아래 표와 같습니다.
| 물품 | 가치 | 무게 |
| 텐트 | 200 | 3 |
| 침낭 | 150 | 2 |
| 스토브 | 50 | 1 |
| 음식 | 100 | 2 |
| 물병 | 100 | 0.5 |
| 구급상자 | 25 | 1 |
총 무게가 배낭 용량인 15kg을 넘지 않으면서, 총 가치가 최대가 되도록 물품을 선택해야 합니다.
배낭 문제는 포트폴리오에 추가할 증권 선택, 원자재 낭비 최소화 방법 모색 등 다양한 분야에서 활용됩니다.
#2. 스케줄링 문제

스케줄링 문제는 작업들을 자원에 최적으로 할당하는 최적화 문제입니다. 여기서 자원은 기계, 인력, 기타 자원 등이 될 수 있습니다.
예를 들어, 프로젝트 관리자가 직원 팀이 완료해야 할 일련의 작업을 스케줄링하는 상황을 가정해 보겠습니다. 각 작업에는 시작 시간, 종료 시간, 그리고 자격 있는 직원 목록이 있습니다.
| 작업 | 시작 시간 | 종료 시간 | 자격 있는 직원 |
| T1 | 9 | 11 | A, B, C |
| T2 | 10 | 12 | A, C |
| T3 | 11 | 13 | B, C |
| T4 | 12 | 14 | A, B |
각 작업을 직원에게 할당하여 총 완료 시간을 최소화해야 합니다.
스케줄링 문제는 기계, 자재, 도구, 노동력 등 자원 배분을 최적화해야 하는 제조 산업, 병상, 인력, 의료 용품 사용을 최적화해야 하는 의료 분야 등 다양한 산업에서 발생합니다. 또한 프로젝트 관리, 공급망 관리, 교육 분야에서도 스케줄링 문제가 발생할 수 있습니다.
#3. 외판원 문제
출처: 위키백과
외판원 문제는 주어진 도시 목록과 각 도시 쌍 사이의 거리가 주어졌을 때, 모든 도시를 한 번씩 방문하고 출발점으로 돌아오는 가장 짧은 경로를 찾는 문제입니다. 이 문제는 동적 프로그래밍을 사용하여 해결할 수 있는 대표적인 최적화 문제입니다.
예를 들어, 여러 도시를 방문해야 하는 영업 사원이라고 가정해 봅시다. 각 도시 사이의 거리는 아래 표와 같습니다.
| 도시 | A | B | C | D | E |
| A | 0 | 10 | 15 | 20 | 30 |
| B | 10 | 0 | 35 | 25 | 15 |
| C | 15 | 35 | 0 | 30 | 20 |
| D | 20 | 25 | 30 | 0 | 10 |
| E | 30 | 15 | 20 | 10 | 0 |
외판원 문제는 관광객을 위한 경로 계획(레저 산업), 상품 운송 계획(물류), 버스 노선 계획(운송), 판매 산업 등 다양한 분야에서 발생할 수 있습니다.
이 외에도 동적 프로그래밍은 많은 실제 응용 프로그램을 가지고 있으며, 추가적인 탐구를 통해 더 자세히 알아볼 수 있습니다.
동적 프로그래밍에 대한 지식을 넓히기 위해, 다음 자료들을 참고해 볼 수 있습니다.
참고 자료
리처드 벨먼의 “동적 프로그래밍”
리처드 벨먼이 저술한 “동적 프로그래밍”은 이 분야를 개척하고 초기 발전에 큰 기여를 한 책입니다.
이 책은 수학과 미적분학의 기본 지식만 있으면 이해할 수 있도록 쉽게 쓰여졌으며, 동적 프로그래밍의 핵심인 다단계 결정 과정의 수학적 이론을 소개합니다.
이후 다단계 생산 과정의 병목 현상 문제, 존재 및 유일성 정리, 최적 재고 방정식 등에 대해 심도 있게 다룹니다.
벨먼은 물류, 스케줄링 이론, 통신 이론, 수리 경제학 및 제어 프로세스 등 다양한 분야의 복잡한 문제들을 예시로 제시하며, 동적 프로그래밍이 이러한 문제들을 어떻게 해결하는지 보여줍니다.
이 책은 킨들, 양장본, 페이퍼백 버전으로 구매할 수 있습니다.
동적 프로그래밍 알고리즘 마스터 코스

Udemy에서 제공하는 이 강좌는 Google 소프트웨어 엔지니어인 Apaar Kamal과 Prateek Narang이 진행합니다.
이 과정은 동적 프로그래밍이 필요한 다양한 문제를 다루는 프로그래밍 대회에서 참가자들이 우수한 성적을 거둘 수 있도록 설계되었습니다.
프로그래밍 대회 참가자뿐만 아니라, 알고리즘에 대한 이해를 높이고자 하는 프로그래머와 프로그래밍 면접, 온라인 코딩 테스트를 준비하는 사람들에게도 유익합니다.
40시간이 넘는 강의를 통해 동적 프로그래밍을 심층적으로 학습할 수 있습니다. 재귀, 백트래킹과 같은 기본 개념을 다시 다루고, 게임 이론, 문자열, 트리, 그래프, 행렬 지수화, 비트 마스크, 조합론, 하위 시퀀스, 분할 문제, 다차원 동적 프로그래밍 등 다양한 주제를 다룹니다.
경쟁적 프로그래밍 필수 요소, 마스터 알고리즘

Udemy에서 Prateek Narang과 Amal Kamaar가 진행하는 이 강좌는 경쟁 프로그래머들에게 유용한 동적 프로그래밍, 수학, 정수 이론, 고급 자료 구조, 알고리즘 등을 다룹니다.
이 강좌는 경쟁적 프로그래밍에 필요한 복잡한 알고리즘과 기술들을 학습하기 전에, 데이터 구조와 알고리즘에 대한 기초를 다지는 데 초점을 맞춥니다.
동적 프로그래밍 외에도 수학, 게임 이론, 패턴 매칭, 비트 마스킹 등 프로그래밍 대회에서 실제로 사용되고 검증된 다양한 고급 알고리즘을 학습할 수 있습니다.
이 과정은 10개의 모듈과 42개의 섹션으로 구성되어 있으며, 각 섹션 후에는 연습 문제를 제공합니다. 경쟁적 프로그래밍에 관심 있는 모든 사람에게 유익한 강좌입니다.
마무리
동적 프로그래밍은 모든 프로그래머가 문제 해결 능력을 향상시키는 데 유용한 기술입니다. 프로그래머들은 위에서 제시된 자료들을 통해 동적 프로그래밍을 학습하고, 실무에 적용할 수 있도록 노력해야 할 것입니다.
다음으로는 데이터 과학에 적합한 프로그래밍 언어에 대해 알아보실 수 있습니다.