| 다이나믹 프로그래밍

메모리를 적절히 사용하여 수행시간 효율성을 비약적으로 향상
이미 계산된 결과 (작은 문제)는 별도의 메모리 영역에 저장하여
다시 계산하지 않고 필요할때 저장했던걸 다시 가져와서 사용
완전 탐색으로 시간이 아주오래 걸리는 것을 다이나믹 프로그래밍으로 하면 시간복잡도를 줄일수 있음
탑다운보텀업 두가지!

  • 탑다운(하향식) : 위 => 아래로
  • 보텀업(상향식) : 아래 => 위

동적 계획법 이라고도 함
일반적인 프로그래밍 분야에서 Dynamic 동적 이란 어떤 의미를 가질까요

  • 자료구조에서 동적 할당(Dynamic Allocation)은 ‘프로그래밍이 실행되는 도중에 실행에 필요한 메모리를 할당 하는 기법’을 말한다
  • 반면에 다이나믹 프로그래밍에서 다이나믹은 기존의 동적을 의미하는 것은 아님 별다른 의미없이 사용된 단어



| 다이나믹 프로그래밍의 조건

다음의 조건을 만족할 때 사용가능

    1. 최적 부분 구조(Optimal Substructure)
      큰 문제를 작은 문제로 나눌 수 있으며 작은 문제의 답을 모아서 큰 문제를 해결할 수 있습니다
    1. 중복되는 부분 문제(Overlapping Subproblem)
      동일한 작은 문제를 반복적으로 해결
      부분 문제가 서로 중첩되어 여러번 등장
      동일한 작은 문제가 반복적으로 호출되어 동일한 문제를 반복적으로 해결되어야할 때



| 피보나치 수열

DP로 풀수있는 대표적인 문제
특정 번째의 값을 구하기 위해 앞에 있는 두수를 더해야한다는 특징이 있다
점화식으로 인접한 항들 사이의 관계식을 표현 할 수 있다

  • 재귀함수로 구현하기

      def fibo(x):
          if x == 1 or x== 2:
              return 1
          return fibo(x-1) + fibo(x-2)
    
      print(fibo(4)) #결과 3  
    

    재귀함수로 피보나치 수열을 구현하게 되면 지수시간 복잡도를 가지게 된다
    중복되는 부분이 여러번 호출된다 (그림)
    이미 해결한 부분에 있어서 해결했던 것이라고 별도의 메모리 공간에 기록해 놓지않으니 이런 상황 발생

  • 다이나믹 프로그래밍으로 해결하기
    다이나믹 프로그래밍 조건 만족하는 지 확인하기
    • 최적 부분 구조 : 큰 문제를 작은 문제로 나눌 수 있다
    • 중복되는 부분 문제 : 동일한 작은 문제를 반복적으로 해결합니다
      => 만족!
  • 다이나믹 프로그래밍 - 탑다운 방식 => 메모이제이션
    한번 계산 된 결과를 메모리공간에 메모
    별도의 테이블에 값을 기록한다는 점에서 캐싱이라고도 함

  • 탑다운
    탑다운은 하향식이라고도 하고 구현과정에서 재귀함수를 이용한다
    큰 문제를 해결하기 위해 작은 문제들을 재귀적으로 호출하여 작은 문제가 모두 해결 되었을 때
    큰 문제의 답까지 얻을 수 있도록 그런 과정에서 한번 계산한 결과값은 저장하기 위해 메모이제이션 방식을 이용한다

      d = [0]*100
      def fibo(x):
          if x ==1 or x==2 : #이렇게 쓰면 fibo(2) fibo(1)는 무조건 계산되는게 아닌가?
              return 1
          if d[x] != 0:
              return d[x]
          d[x] = fibo[x-1] + fibo[x-2]
          return d[x]
    
      print(fibo(99))
    
  • 보텀업
    상향식 아래쪽부터 작은 문제를 하나씩 해결해 나가면서 먼저 해결했던 계산값을 활용하면서 그다음까지 해결해 나간다
    결과 저장용 리스트는 DP 테이블 이라고 한다
    메모이제이션은 이전에 계산된 결과를 일시적으로 기록해 놓는 넓은 개념을 의미
    메모이제이션은 DP에 국한된 개념은 아님

      d = [0]*100
      d[1] =1
      d[2] =1
      n =99
    
      for i in range(3,n-1):
          d[i] = d[i-1] + d[i-2]
    
      print(d[n])
    

    => 시간 복잡도는 O(N) 이된다



| 다이나믹 프로그래밍 VS 분할 정복

최적 부분 구조를 가질 때 사용할 수 있다
큰 문제를 작은문제로 나누어 작은 문제의 답을 모아 큰 문제를 해결할 수 있는 상황

다이나믹 프로그래밍과 분할 정복의 차이점은 부분 문제의 중복
다이나믹 프로그래밍은 각 부분 문제들이 서로 영향을 미치며 부분 문제가 중복 작은 문제가 반복적으로 호출
분할 정복 문제는 동일한 부분 문제가 반복적으로 계산 되지 않는다

  다이나믹 프로그래밍 분할 정복
최적 부분 구조 O O
부분 문제의 중복 O X



| 다이나믹 프로그래밍 문제에 접근하는 방법

주어진 문제가 다이나믹 프로그래밍 유형임을 파악하는 것이 중요
가장 먼저 그리디 , 구현, 완전 탐색으로 해결할 수 있는지 검토
=> 완전탐색은 시간복잡도가 많이 소요된다 판단되면 DP
작은 문제로 큰 문제를 해결 할 수 있으며 중복되는 특성이 있으면 DP



| :bell: 메모

탑다운 방식 보텀업 방식 암기!

댓글남기기