๐Ÿ“Œ๋™์  ๊ณ„ํš๋ฒ•(Dynamic Programming, DP)

JP Kimยท2024๋…„ 11์›” 13์ผ

์•Œ๊ณ ๋ฆฌ์ฆ˜

๋ชฉ๋ก ๋ณด๊ธฐ
2/2

๋™์  ๊ณ„ํš๋ฒ•(Dynamic Programming)

๋™์  ๊ณ„ํš๋ฒ•(Dynamic Programming)์€

  • ๋ฌธ์ œ์˜ ์ตœ์ ํ•ด๊ฐ€ ํ•˜์œ„ ๋ฌธ์ œ(sub-problem)์˜ ์ตœ์ ํ•ด๋กœ ์ •์˜๋˜๋ฉฐ,
  • ํ•˜์œ„ ๋ฌธ์ œ๊ฐ€ ์ค‘์ฒฉ(overlapping)๋  ๋•Œ

์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ธฐ๋ฒ•์ด๋‹ค.

์˜ˆ์‹œ๋กœ, ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด์„ ์žฌ๊ท€์™€ DP๋กœ ๊ตฌํ•˜๋Š” ๋ฐฉ์‹์„ ๋น„๊ตํ•ด๋ณด์ž.


1. ์žฌ๊ท€

import time

#์žฌ๊ท€ ํ•จ์ˆ˜
def Fibonacci(n):
	if n == 1 or n == 2:
       return 1
   else:
       return Fibonacci(n-1) + Fibonacci(n-2)
       
n = 40
   
startTime = time.time()
result = Fibonacci(n)
endTime = time.time()
timeRecursive = endTime - startTime
   
print(f"Fibonacci({n}) ๊ณ„์‚ฐ ๊ฒฐ๊ณผ")
print(f"๊ฐ’ : {result} / ์‹คํ–‰ ์‹œ๊ฐ„ {timeRecursive}์ดˆ")
  • ์‹คํ–‰๊ฒฐ๊ณผ
    Fibonacci(40) ๊ณ„์‚ฐ ๊ฒฐ๊ณผ
    ๊ฐ’ : 102334155 / ์‹คํ–‰ ์‹œ๊ฐ„ 29.934786319732666์ดˆ
  • ์‹œ๊ฐ„ ๋ณต์žก๋„ : O(2^n)

์ด ์žฌ๊ท€ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ณผ์ •์„ ์‚ดํŽด๋ณด๋ฉด, ๋™์ผํ•œ ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ์ด๋กœ ์ธํ•ด ์‹คํ–‰๊ณผ์ •์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๊ฒŒ ๋œ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์ด ๊ณผ์ •์„ ์ž˜ ์‚ดํŽด๋ณด๋‹ˆ

  • ๊ฐ™์€ ํ•˜์œ„ ๋ฌธ์ œ(sub-problem)๊ฐ€ ์ค‘์ฒฉ๋˜๊ณ 
    ex) Fibo(n-k)๊ฐ€ ๋ฐ˜๋ณต๋จ
  • ์ตœ์ข…์ ์ธ ํ•ด๊ฐ€ ํ•˜์œ„ ๋ฌธ์ œ์˜ ํ•ด๋กœ ์ •์˜๋œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
    ex) Fibo(n) = Fibo(n-1) + Fibo(n-2)

์ฆ‰ ์ด ๋ฌธ์ œ๋Š” DP๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.
์ด์ œ ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด์„ DP๋กœ ํ•ด๊ฒฐํ•ด๋ณด์ž.


2. ๋™์  ๊ณ„ํš๋ฒ•

import time

# ๋™์  ๊ณ„ํš๋ฒ•
def Fibonacci_DP(n):
    if n == 1 or n == 2:
        return 1

    fibo = [0 for _ in range(n+1)]

    fibo[1], fibo[2] = 1, 1

    for i in range(3, n+1):
        fibo[i] = fibo[i-1] + fibo[i-2]

    return fibo[n]


n = 10000

startTime = time.time()
result = Fibonacci_DP(n)
endTime = time.time()
timeDP = endTime - startTime

print(f"Fibonacci({n}) ๊ณ„์‚ฐ ๊ฒฐ๊ณผ")
print(f"๊ฐ’ : {result} / ์‹คํ–‰ ์‹œ๊ฐ„ {timeDP}์ดˆ")
  • ์‹คํ–‰๊ฒฐ๊ณผ
Fibonacci(10000) ๊ณ„์‚ฐ ๊ฒฐ๊ณผ
๊ฐ’ : 33644764876...(์ƒ๋žต) / ์‹คํ–‰ ์‹œ๊ฐ„ 0.00937342643737793์ดˆ
  • ์‹œ๊ฐ„ ๋ณต์žก๋„ : O(n)

์žฌ๊ท€์™€ DP์˜ ์‹คํ–‰ ์‹œ๊ฐ„์„ ๋น„๊ตํ•ด๋ณด๋ฉด, DP๋ฐฉ์‹์ด ์žฌ๊ท€๋ฐฉ์‹๋ณด๋‹ค ๋งค์šฐ ๋น ๋ฅธ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.


ํƒ‘๋‹ค์šด(Top-Down)๊ณผ ๋ฐ”ํ…€์—…(Bottom-Up)

๋ฐฉ๊ธˆ ์ „ ๋ฌธ์ œ์˜ ๊ฒฝ์šฐ, ๋ฐ”ํ…€์—…(Bottom-Up) ์ ‘๊ทผ ๋ฐฉ์‹์„ ํ†ตํ•ด ๋ฌธ์ œ๋ฅผ ํ’€์—ˆ๋‹ค.
DP๋Š” ์ฃผ๋กœ ํƒ‘๋‹ค์šด(Top-Down)๊ณผ ๋ฐ”ํ…€์—…(Bottom-Up) ์ ‘๊ทผ๋ฐฉ์‹์„ ํ†ตํ•ด์„œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค.


1. ํƒ‘๋‹ค์šด

ํƒ‘๋‹ค์šด์€ ์œ„์—์„œ๋ถ€ํ„ฐ ์•„๋ž˜๋กœ, ์ฆ‰ ํฐ ๋ฌธ์ œ์—์„œ ์‹œ์ž‘ํ•ด์„œ ํ•„์š”ํ•œ ํ•˜์œ„๋ฌธ์ œ์˜ ํ•ด๋ฅผ ๊ตฌํ•ด๊ฐ€๋Š” ๋ฐฉ์‹์ด๋‹ค.

ํƒ‘๋‹ค์šด ๋ฐฉ์‹์˜ ๊ฒฝ์šฐ, ์žฌ๊ท€์™€ ๋ฉ”๋ชจ์ œ์ด์…˜(Memoization)์„ ํ™œ์šฉํ•œ๋‹ค.

๋ฉ”๋ชจ์ œ์ด์…˜(Memoization) : ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ณผ์ •์—์„œ ์ด๋ฏธ ๊ณ„์‚ฐํ•œ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•ด์„œ ์ค‘๋ณต ๊ณ„์‚ฐ์„ ๋ฐฉ์ง€ํ•˜๋Š” ๊ธฐ๋ฒ• ์ค‘ ํ•˜๋‚˜

  • ํƒ‘๋‹ค์šด์  ์ ‘๊ทผ ๋ฐฉ์‹
  • ์žฌ๊ท€ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๊ตฌํ˜„๋œ๋‹ค.
  • ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ฉฐ ํ•„์š”ํ•œ ๋ถ€๋ถ„ ๋ฌธ์ œ๋งŒ ๊ณ„์‚ฐ๋˜์–ด ์ €์žฅ๋œ๋‹ค.

์•ž์„œ ํ’€์–ด๋ณธ ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด์„ ํƒ‘๋‹ค์šด ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

# ๋™์  ๊ณ„ํš๋ฒ• (ํƒ‘๋‹ค์šด)
def Fibonacci_DP(n, memo = {}):
    if n in memo:
        return memo[n]

    if n <= 1:
        return n
    
    memo[n] = Fibonacci_DP(n-1, memo) + Fibonacci_DP(n-2, memo)

    return memo[n]

print(Fibonacci_DP(20)) # ์ถœ๋ ฅ 6765

Fibonacci_DP ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด์„œ ์œ„์—์„œ๋ถ€ํ„ฐ ์žฌ๊ท€์ ์œผ๋กœ ์ˆ˜์—ด์„ ๊ณ„์‚ฐํ•˜๋ฉด์„œ, ๊ณ„์‚ฐ๋œ ๊ฒฐ๊ณผ๋Š” memo ๋”•์…”๋„ˆ๋ฆฌ์— ์ €์žฅํ•˜๋ฉฐ ์ค‘๋ณต ๊ณ„์‚ฐ์„ ํ”ผํ•˜๊ณ  ์žˆ๋‹ค.


2. ๋ฐ”ํ…€์—…

๋ฐ”ํ…€์—…์€ ์•„๋ž˜์—์„œ๋ถ€ํ„ฐ ์œ„๋กœ, ์ฆ‰ ์ž‘์€ ํ•˜์œ„๋ฌธ์ œ์—์„œ ์‹œ์ž‘ํ•ด ๋” ํฐ ๋ฌธ์ œ์˜ ํ•ด๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

๋ฐ”ํ…€์—… ๋ฐฉ์‹์˜ ๊ฒฝ์šฐ, ๋ฐ˜๋ณต๋ฌธ๊ณผ ํƒ€๋ทธ๋ ˆ์ด์…˜(Tabulation)์„ ํ™œ์šฉํ•œ๋‹ค.

ํƒ€๋ทธ๋ ˆ์ด์…˜(Tabulation) : ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ณผ์ •์—์„œ ์ด๋ฏธ ๊ณ„์‚ฐํ•œ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•ด์„œ ์ค‘๋ณต ๊ณ„์‚ฐ์„ ๋ฐฉ์ง€ํ•˜๋Š” ๊ธฐ๋ฒ• ์ค‘ ํ•˜๋‚˜

  • ๋ฐ”ํ…€์—…์  ์ ‘๊ทผ ๋ฐฉ์‹
  • ๋ฐ˜๋ณต๋ฌธ์„ ํ†ตํ•ด ๊ตฌํ˜„๋œ๋‹ค.
  • ๋ชจ๋“  ๋ถ€๋ถ„ ๋ฌธ์ œ๋ฅผ ๊ณ„์‚ฐํ•ด์„œ ์ž‘์€ ๊ฒƒ๋ถ€ํ„ฐ ์ˆœ์ฐจ์ ์œผ๋กœ ์ €์žฅํ•œ๋‹ค.

์•ž์„œ ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ์‚ดํŽด๋ณด์ž.

# ๋™์  ๊ณ„ํš๋ฒ• (๋ฐ”ํ…€์—…)
def Fibonacci_DP(n):
    if n == 1 or n == 2:
        return 1

    fibo = [0 for _ in range(n+1)]

    fibo[1], fibo[2] = 1, 1

    for i in range(3, n+1):
        fibo[i] = fibo[i-1] + fibo[i-2]

    return fibo[n]
    
print(Fibonacci_DP(20)) # ์ถœ๋ ฅ 6765

Fibonacci_DP ํ•จ์ˆ˜ ๋‚ด์—์„œ fibo๋ฆฌ์ŠคํŠธ์˜ ์ธ๋ฑ์Šค๊ฐ€ 1๊ณผ 2์ผ ๋•Œ ๊ฐ’์„ 1๋กœ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค. (๊ธฐ์ € ์กฐ๊ฑด(Base Case))
๊ทธ๋ฆฌ๊ณ  ๋ฐ˜๋ณต๋ฌธ์„ ํ†ตํ•ด 3์—์„œ n๊นŒ์ง€ ์ˆœ์ฐจ์ ์œผ๋กœ ์ˆ˜์—ด์„ ๊ณ„์‚ฐํ•˜๊ณ  fibo๋ฆฌ์ŠคํŠธ์— ์ €์žฅํ•œ๋‹ค.


์ •๋ฆฌ

ํ•ญ๋ชฉํƒ‘๋‹ค์šด(Top-Down)๋ฐ”ํ…€์—…(Bottom-Up)
๊ตฌํ˜„ ๋ฐฉ์‹์žฌ๊ท€์™€ ๋ฉ”๋ชจ์ด์ œ์ด์…˜๋ฐ˜๋ณต๋ฌธ๊ณผ ํƒ€๋ทธ๋ ˆ์ด์…˜(ํ˜น์€ ํ…Œ์ด๋ธ”)
๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ์žฌ๊ท€ ํ˜ธ์ถœ ์Šคํƒ + ์บ์‹œํ…Œ์ด๋ธ”์— ๋ชจ๋“  ๋ถ€๋ถ„ ๋ฌธ์ œ ๊ฒฐ๊ณผ ์ €์žฅ
์ฝ”๋“œ ๋ณต์žก๋„์žฌ๊ท€ ํ•จ์ˆ˜ ์‚ฌ์šฉ์œผ๋กœ ์ฝ”๋“œ๊ฐ€ ๊ฐ„๊ฒฐํ•  ์ˆ˜ ์žˆ์Œ๋ฐ˜๋ณต๋ฌธ๊ณผ ํ…Œ์ด๋ธ” ์ดˆ๊ธฐํ™” ๋“ฑ์œผ๋กœ ๋‹ค์†Œ ๋ณต์žกํ•  ์ˆ˜ ์žˆ์Œ
๊ณ„์‚ฐ ์ˆœ์„œํ•„์š”ํ•œ ๋ถ€๋ถ„ ๋ฌธ์ œ๋ถ€ํ„ฐ ์žฌ๊ท€์ ์œผ๋กœ ๊ณ„์‚ฐ์ž‘์€ ๋ฌธ์ œ๋ถ€ํ„ฐ ์ˆœ์ฐจ์ ์œผ๋กœ ๊ณ„์‚ฐ

ํ…Œ์ด๋ธ”(table) : ๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌ์กฐํ™”ํ•˜์—ฌ ์ €์žฅํ•˜๊ณ , ํšจ์œจ์ ์œผ๋กœ ๊ฒ€์ƒ‰ํ•˜๊ฑฐ๋‚˜ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“  ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋กœ,
์—ฌ๊ธฐ์„  ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋ถ€๋ถ„ ๋ฌธ์ œ์˜ ํ•ด๋‹ต์„ ์ €์žฅํ•˜๋Š” ๋ฐฐ์—ด ๋˜๋Š” ๋ฆฌ์ŠคํŠธ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

์บ์‹œ(cache) : ๋ฐ์ดํ„ฐ๋‚˜ ๊ณ„์‚ฐ ๊ฒฐ๊ณผ๋ฅผ ์ž„์‹œ๋กœ ์ €์žฅํ•ด ๋‘์—ˆ๋‹ค๊ฐ€ ํ•„์š”ํ•  ๋•Œ ๋น ๋ฅด๊ฒŒ ๊บผ๋‚ด ์“ฐ๋Š” ์ €์žฅ์†Œ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.


๋ถ„ํ•  ์ •๋ณต(Divide and Conquer)๊ณผ ๋™์  ๊ณ„ํš๋ฒ•(Dynamic Programming)

๋ฌธ์ œ๋ฅผ ํ•˜์œ„๋ฌธ์ œ๋กœ ์ชผ๊ฐœ๊ณ , ๊ทธ ํ•˜์œ„๋ฌธ์ œ์˜ ๋ถ€๋ถ„ํ•ด๋ฅผ ํ†ตํ•ด์„œ ์ „์ฒด ๋ฌธ์ œ์˜ ํ•ด๋ฅผ ๊ตฌํ•œ๋‹ค๋Š” ์ธก๋ฉด์—์„œ ๋ถ„ํ•  ์ •๋ณต(Divide and Conquer)๊ณผ ๋™์  ๊ณ„ํš๋ฒ•(Dynamic Programming)์€ ๋™์ผํ•˜๊ฒŒ ๋ณด์ด๊ธฐ๋„ ํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ์ ‘๊ทผ ๋ฐฉ์‹๊ณผ ์ ์šฉ๋˜๋Š” ๋ฌธ์ œ์˜ ํŠน์„ฑ์—์„œ ๋‘˜์€ ๋ช‡ ๊ฐ€์ง€ ์ค‘์š”ํ•œ ์ฐจ์ด์ ์ด ์žˆ๋‹ค.


divede ์˜คํƒ€๋‚ฌ๋‹ค.

  • ๋ถ„ํ•  ์ •๋ณต(Divide and Conquer)

    • ํ•˜์œ„ ๋ฌธ์ œ๊ฐ€ ์„œ๋กœ ๋…๋ฆฝ์ ์ด๋ฉฐ, ์ค‘๋ณต๋˜์ง€ ์•Š์Œ
    • ๋ฌธ์ œ๋ฅผ ์—ฌ๋Ÿฌ ํ•˜์œ„ ๋ฌธ์ œ๋กœ ๋ถ„ํ• ํ•œ ํ›„, ๋ถ€๋ถ„ํ•ด๋ฅผ ๊ฒฐํ•ฉํ•ด์„œ ์ „์ฒดํ•ด๋ฅผ ๊ตฌํ•œ๋‹ค.

      ์˜ˆ์‹œ : ๋ณ‘ํ•ฉ ์ •๋ ฌ(Merge Sort), ํ€ต ์ •๋ ฌ(Quick Sort), ์ด์ง„ ํƒ์ƒ‰(Binary Search)

  • ๋™์  ๊ณ„ํš๋ฒ•(Dynamic Programming)

    • ํ•˜์œ„ ๋ฌธ์ œ๊ฐ€ ์ค‘์ฒฉ๋˜๋ฉฐ ์—ฌ๋Ÿฌ ๋ฒˆ ๊ณ„์‚ฐ๋จ
    • ํ•˜์œ„ ๋ฌธ์ œ์˜ ๋ถ€๋ถ„ํ•ด๋ฅผ ์ €์žฅํ•ด๋†จ๋‹ค๊ฐ€ ์žฌ์‚ฌ์šฉํ•˜๋ฉฐ ์ „์ฒดํ•ด๋ฅผ ๊ตฌํ•œ๋‹ค.

      ์˜ˆ์‹œ : ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด, LCS(์ตœ์žฅ ๊ณตํ†ต ๋ถ€๋ถ„ ์ˆ˜์—ด), ๋ง‰๋Œ€ ์ž๋ฅด๊ธฐ ๋ฌธ์ œ


์—ฌ๋‹ด

๋™์  ๊ณ„ํš๋ฒ•์˜ ์ด๋ฆ„์„ ๋ณด๋ฉด ๋™์ (dynamic)์ด๋ผ๋Š” ๋ง์ด ๋ถ™์–ด์žˆ๋Š”๋ฐ, ์•ž์„œ ์‚ดํŽด๋ณธ ๊ฒƒ์ฒ˜๋Ÿผ, ์‚ฌ์‹ค ์ด ๊ธฐ๋ฒ•์€ ๋™์ ๊ณผ๋Š” ๊ฑฐ๋ฆฌ๊ฐ€ ๋ฉ€๋‹ค.
๊ทธ๋Ÿฐ๋ฐ๋„ ์ด๋ฆ„์ด ์ด๋Ÿฐ ์ด์œ ๋Š”, ๋™์  ๊ณ„ํš๋ฒ•์˜ ๊ณ ์•ˆ์ž๊ฐ€ dynamic์ด๋ž€ ์ด๋ฆ„์ด ๋ฉ‹์ ธ๋ณด์—ฌ์„œ ๋ถ™์˜€๊ธฐ์— ์ด๋Ÿฐ ์ด๋ฆ„์œผ๋กœ ์ •ํ•ด์ง€๊ฒŒ ๋˜์—ˆ๋‹ค.

profile
๋‹น์‹ ์„ ํ•œ ์ค„๋กœ ์†Œ๊ฐœํ•ด๋ณด์„ธ์š”

0๊ฐœ์˜ ๋Œ“๊ธ€