ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 동적계획법(Dynamic Programming)
    Algorithm/Algorithm_Theory 2022. 9. 12. 11:49

    Dynamic Programming이란?!

    특정 값을 얻기 위해 매번 같은 결과를 반환하는 연산을 굳이 반복해서 수행한다면 문제를 효율적으로 해결할 수 없다.(재귀함수). 한 번 계산한 결과를 재활용하는 방식

    Dynamic Programming 조건

    1) 최적 부문 구조 (Optimal Substructure)
    
    - 부문 문제들의 최적의 답을 이용해서 기존 문제의 최적의 답을 구할 수 있다는 것
    
    ex) 
    
    피보나치 5번째의 수, fib(5)..(1,1,2,3,5..) 를 구한다고 했을 때 fib(3)과 fib(4)
    
    2) 중복되는 부분 문제(Overlapping Subproblems)
    
    - fib(7)을 알아내기 위해, fib(5)를 2번씩이나..fib(4)를 3번씩이나..구하는것

     

    재귀함수(Recursive Function) vs 동적계획법(Dynamic Programming) 

     

    재귀함수로 피보나치를 구현

    # 재귀함수로 피보나치를 구해보자 
    
    def solution(n):
        answer = 0
        if n == 0:
            return 0
        elif n == 1:
            return 1
        return solution(n-1) + solution(n-2)
    
    solution(10) # 55

    f3이 3번이나 호출되었다(비효율)

     

    Dynamic Programming으로 피보나치를 구현

    • 1) 탑 다운(Top-Down, 하향식) 방식: 가장 큰 문제부터 시작하여 작은 문제 순으로 답을 찾아가는 방식으로, 주로 재귀 함수 활용
    • 2) 바텀 업(Bottom-Up, 상향식) 방식: 가장 작은 문제의 답부터 찾아가는 방식으로, 주로 반복문 활용

    탑 다운 방식보다 바텀 업 방식을 활용했을 때 다이나믹 프로그래밍의 성능이 좋다

    다이나믹 프로그래밍을 구현한다고 하면 일반적으로 바텀 업 방식

     

    # Top-Down   
    # 한계점?!
    - 재귀함수를 사용하기 때문에, *오버헤드(ovehead)가 발생
    
    m = [0] * 100 
    
    def solution(n):
        if n == 0:
            return 0
        if n == 1:
            return 1
        if m[n] != 0:
            return m[n]     
        m[n] = solution(n-1) + solution(n-2)
        return m[n]
      
    solution(10)

    더보기

    * 오버헤드(overhead)란?

    오버헤드란 어떤 연산을 수행하기 위해 필요한 간접적인 시간 또는 메모리 등을 말합니다. 예를 들어, A라는 연산을 처리하기 위해 7초가 소요되고 안정성 등을 위해 추가적으로 B라는 처리까지 수행하는 데 10초가 걸렸다고 하죠. 그렇다면 여기서 오버헤드는 3초가 됩니다. 나아가, 만약 B라는 처리 효율을 개선하여 A와 B를 처리하는데 8초가 걸렸다면, 2초의 오버헤드를 단축시켰다고 말할 수 있습니다.

    # bottom-up
    # bottom-up 방식에서 결괏값을 저장해 두는 리스트를 DP 테이블이라고 한다.
    
    m = [0] * 100 
    m[0] = 0
    m[1] = 1  
    
    def solution(n):
        for i in range(2, n+1):
            m[i] = m[i-1] + m[i-2]         
        return m[n]
        
    solution(10)

    Dynamic Programming 구현 방식

    1) Memoization(Top-down)

    - 중복되는 계산은 한 번만 계산 후에 저장 해 놓고 필요할 때 마다 꺼내쓰는 방법

    - 재귀를 기반으로 코드를 작성한다

    def fib_memo(n, cache):
        # 코드를 작성하세요.
        if n == 1 or n ==2:
            return 1
            
        if n in cache:
            return cache[n]
        cache[n] = fib_memo(n-1, cache) + fib_memo(n-2, cache)
        return cache[n]
            
        
    
    
    def fib(n):
        # n번째 피보나치 수를 담는 사전
        fib_cache = {}
    
        return fib_memo(n, fib_cache)
    
    
    # 테스트
    print(fib(10))
    print(fib(50))
    print(fib(100))

    2) Tablulation(bottom-up)

    - 가장 작은 문제의 답부터 찾아가는 방식으로, 주로 반복문 활용

    -  for 반복문으로 코드를 작성한다 

     

    def fib_tab(n):
        # 코드를 작성하세요.
        # 계산된 피보나치 수를 저장시켜 놓을 표(table)
        fib_table = [0,1,1]
        for i in range(n+1):
            if i >=3: 
                number = fib_table[i-1] + fib_table[i-2]
                fib_table.append(number)
        return fib_table[n]      
        
    
    # 테스트
    print(fib_tab(10))
    print(fib_tab(56))
    print(fib_tab(132))

    memozation 과 Tabulation 공통점 
    - 둘다 중복되는 부문 문제의 비효율을 해결 

     

    memozation 문제점 
    - memo는 재귀를 사용하기 때문에  stack이 쌓이고 오류가 날 수 있따 

     

    tabulation 은 반복문을 사용하기 떄문에 그럴 위험이 X 
    하지만 tabluation은 테이블 형태로 첫번째 값부터  채워나가는 것이기 때문에 
    필요 없는 값도 구한다 

    - 시간복잡도: O(n) 
    - 공간복잡도: O(n) 

    => 따라서 이러한 문제점을 해결하기 위해서 가장 최근 2개의 값만 사용하면은 된다?!
    사용하는 메모리는 고정되어 있기 때문에 공간 복잡도 0(1) 

    def fib_optimized(n):
        # 코드를 작성하세요. 
        # 1,1,2,3,5,8...
        current = 1 
        previous = 0 
        for i in range(1,n):
            current_copy  = current 
            current = previous + current 
            previous = current_copy 
        return current          
    
        
        
    
    
    # 테스트
    print(fib_optimized(16))
    print(fib_optimized(53))
    print(fib_optimized(213))

     

    # 출처: https://heytech.tistory.com/65#

     

    [알고리즘] 다이나믹 프로그래밍(DP)에 대해 알아보자! (+Python 구현)

    본 포스팅에서는 다이나믹(동적) 프로그래밍에 대해 알아봅니다. 📚 목차 1. 다이나믹 프로그래밍이란? 2. 다이나믹 프로그래밍 예제 3. 재귀함수 기반 구현 3.1. 소스코드 3.2. 문제점 3.2.1. 연산

    heytech.tistory.com

    # 출처: 코드잇

    'Algorithm > Algorithm_Theory' 카테고리의 다른 글

    너비우선탐색(BFS, Breadh-Frist Search)  (0) 2022.11.23
    스택(Stack)  (0) 2022.11.14
    큐(Queue)  (1) 2022.11.13
    그리디알고리즘(Greedy Algorithm)  (0) 2022.10.22
    브루트포스(BruteForce)  (0) 2022.10.10

    댓글

Designed by Tistory.