Dynamic Programming
Step by Step
ZeroPage 25기 박인서
시작 하기에 앞서서
 C언어 모르시는 분?
 컴퓨터에 C언어/C++ IDE를 켜 주세요
 Visual Studio, CLion, Codeblock 등
 실습을 하기 위함입니다.
 문제는 http://acmicpc.net/, http://dovelet.com/ 에서 가져왔습니다.
Dynamic Programming
 한국어로는 동적 계획법
 사실 그냥 멋있어서.. By 제작자
 문제를 작은 문제로 나누는 것에서 출발
Dynamic Programming
문제
Dynamic Programming
문제를 푸는 법
문제를 나눈다.
문제를 푼다.
결과를 합친다. 끄읕
이런 방식을 Divide & Conquer라고 함.
Fibonacci 함수
 피보나치 함수란?
 F(0)=0, F(1)=1, F(n) = F(n-1) + F(n-2)(n>=2)
 기본 정의에 의한 Fibonacci 함수 구현
Fibonacci 함수
 Fibonacci 함수 실행 모습
 중복이 많이 발생
 중복에 대한 결과를 미리 저장하면?
Memoization(메모이제이션)
 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장
함으로써 동일한 계산의 반복 수행을 제거하여 프로그램 실행 속도
를 빠르게 하는 기술
 Dynamic Programming의 핵심이 되는 기술
 Memoization을 이용한 Fibonacci
문제를 풀어봅시다.
 2748 – 피보나치 수 2
이항 계수
 주어진 크기의 조합의 가지 수
 주요 공식

𝑛
𝑟
= 𝑛 𝐶𝑟 =
𝑛!
𝑟!× 𝑛−𝑟 !
(0 ≤ 𝑟 ≤ 𝑛)

𝑛
𝑟
=
𝑛 − 1
𝑟 − 1
+ (
𝑛 − 1
𝑟
)

𝑛
𝑟
=
𝑛
𝑛 − 𝑟

𝑛
0
=
𝑛
𝑛
= 1
이항 계수
 재귀 호출을 이용한 이항 계수
 Memoization을 이용한 이항 계수
문제를 풀어봅시다.
 11051 – 이항 계수 2
구간 합 구하기
30 80 50 90 70 100 10 20 40 60
I J
 임의의 I번째 수부터 J번째 수까지의 구간의 합
구간 합 구하기
 일반적인 방법(for문 이용)
 매번 이렇게 계산을 해야 함..
 시간 복잡도 : O(n)
구간 합 구하기
 구간 합에서 Memoization을 하려면 어떻게 해야 할까요?
 첫번째 수 부터 자신 까지의 누적 합을 저장
 (I번째 수~J번째 수의 누적 합) = Data[J] - Data[I-1]
 시간 복잡도 : O(1)
입력 30 80 50 90 70 100 10 20 40 60
누계 30 110 160 250 320 420 430 450 490 550
I J
문제를 풀어봅시다.
 11659 – 구간 합 구하기 4 (유사 문제 : 11441 - 합 구하기)
2차원 구간 합
1. 2중 For문 사용
 그 때 그 때 더해줌 – 시간 복잡도 O(n^2)
2. 1개 For문 사용
 1차원 누적 합 X N개 – 시간 복잡도 O(n)
3. For문 미사용
 2차원 누적 합 이용 – 시간 복잡도 O(1)
2차원 구간 합
(a, b)
(c, d)
2차원 구간 합
(a, b)
(c, d)
2차원 구간 합
 2차원 누적 합 구하기
 포함 배제의 원리를 이용
 Data[I][J] = Data[I-1][J] + Data[I][J-1] – Data[I-1][J-1]+A[I][J]
(1, 1)
(a, b)
2차원 구간 합
(a, b)
(c, d)
2차원 구간 합
A B
C D
문제를 풀어봅시다.
 11660 – 구간 합 구하기 5 (유사 문제 : 11441 - 합 구하기)
LIS(최대 증가 부분 수열)
Longest Increasing Subsequence
가장 긴 증가하는 부분 수열
각각의 index에서의 LIS의 길이를 알아야 함
시간복잡도 : O(n^2)
입력 30 80 50 90 70 10 100 20 40 60
LIS 1 2 2 3 3 1 4 2 3 4
문제를 풀어봅시다.
1965 – 상자넣기
LIS(최대 증가 부분 수열)
참고) 하지만 시간을 더 줄일 수 있습니다.
시간복잡도 : O(nlogn)
LIS 1 2 3 4
값 30 80 90 100
10 50 70 60
20 40
입력 30 80 50 90 70 10 100 20 40 60
LIS 1 2 2 3 3 1 4 2 3 4
문제를 풀어봅시다.
1365 – 꼬인 전깃줄
동전 교환 문제
거스름 돈의 동전을 최소 개수로 주고 싶음
무조건 큰 거 부터? – No
동전이 1원, 4원, 6원 – 거스름돈 8원
Dynamic Programming 이용
가격 1 2 3 4 5 6 7 8
갯수 1 2 3 1 2 1 2 2
문제를 풀어봅시다.
2294 – 동전 2
배낭 채우기 문제
 Knapsack Problem 이라고도 함.
 무게 W와 가치 V가 주어질 때, 가치가 최대가 되게끔..
𝑚𝑎𝑥:
𝑖=1
𝑁
𝑣𝑖 ∙ 𝑥𝑖
subject to
𝑖=1
𝑁
𝑤𝑖 ∙ 𝑥𝑖 ≤ 𝐶
𝑥𝑖 ∈ 0,1 , 𝑖 ∈ 1, ⋯ , 𝑁
and 𝑥𝑖 is decision variable which defines the selection of 𝐼𝑖
배낭 채우기 문제
Product A Only
Product A and
Product B
배낭 채우기 문제
문제를 풀어봅시다.
Dovelet 21단계 0/1 knapsack
Dynamic Programming 정리
보다 자세한 사항은..
 2학년 2학기 알고리즘분석/3학년 1학기 알고리즘 수업에서..
 알고리즘 학회 ChAOS(Chung-ang Algorithm Organization and
Study)로 오셔서..
출처
 김중헌 교수님 알고리즘 분석 강의록
 알고리즘 문제해결 전략 세트, 구종만 저
 약간의 블로그 참조..

Dynamic Programming : Step by Step