다라다라V
article thumbnail
728x90
반응형
본 글은 "나동빈"님의 [이것이 코딩 테스트다]를 참고하여 작성하였으며, 필자가 직접 문제를 풀며 관련된 문제들을 찾아 정리하였습니다.

시리즈 보기
[코테 알고리즘] 파이썬 기본 / 관련 문제
[코테 알고리즘] 파이썬 주요 라이브러리 / 관련 문제
[코테 알고리즘] 그리디 / 관련 문제
[코테 알고리즘] 구현 / 관련 문제
[코테 알고리즘] DFS, BFS / 관련 문제
[코테 알고리즘] 정렬 / 관련 문제
[코테 알고리즘] 다이나믹 프로그래밍 / 관련 문제
[코테 알고리즘] 최단 경로 / 관련 문제
[코테 알고리즘] 그래프 이론 / 관련 문제

 

다이나믹 프로그래밍 개요

  • 다이나믹 프로그래밍의 2가지 방식
    • 탑다운
      • 재귀 함수를 이용
      • 큰 문제를 해결하기 위해 작은 문제를 호출
    • 바텀업
      • 반복문을 이용
      • 작은 문제를 먼저 해결하고, 해결된 작은 문제를 모아 큰 문제를 해결
  • 메모이제이션 기법을 주로 사용하여 구현

 

다이나믹 프로그래밍

  • 큰 문제를 작게 나누고, 같은 문제라면 한 번씩만 풀어 문제를 효율적으로 해결
    1. 큰 문제를 작은 문제로 나눌 수 있다.
    2. 작은 문제에서 구현한 정답은 그것을 포함하는 큰 문제에서도 동일하다
  • 메모이제이션
    • = 캐싱
    • 다이나믹 프로그래밍을 구현하는 방법 중 하나
    • 한 번 구한 결과를 메모리 공간에 메모해두고 같은 식을 다시 호출하면 메모한 결과를 그대로 가져오는 방법
    • 리스트에 값을 구현
  • 다이나믹 프로그래밍 사용 조건
    1. 최적 부분 구조 (Optimal Substructure)
      • 큰 문제를 작은 문제로 나눌 수 있으며 작은 문제의 답을 모아서 큰 문제를 해결
    2. 중복되는 부분 문제 (Overlapping Subproblem)
      • 동일한 작은 문제를 반복적으로 해결해야 함

 

피보나치

### 피보나치 수열 소스 코드 (재귀적)

# 한 번 계산된 결과를 메모이제이션(Memoization)하기 위한 리스트 초기화
d = [] * 100

# 피보나치 함수(Fibonacci Function)를 재귀함수로 구현(탑다운 프로그래밍)
def fibo(x):
    # 종료 조건
    if x == 1 or x == 2:
        return 1
    # 이미 계산한 적있는 문제라면 그대로 반환
    if d[x] != 0:
        return d[x]
    # 아직 계산하지 않은 문제라면 점화식에 따라서 피보나치 결과 반환
    d[x] = fibo(x - 1) + fibo(x - 2)
    return d[x]

 

다이나믹 프로그래밍 vs 퀵 정렬

  • 퀵 정렬
    • 정렬을 수행할 때 정렬할 리스트를 분할하며 전체적으로 정렬
    • 분할 정복 알고리즘 중 하나
  • 다이나믹 프로그래밍
    • 큰 문제를 작게 나누고, 같은 문제라면 한 번씩만 풀어 문제를 효율적으로 해결
    • 다이나믹 프로그래밍은 문제들이 서로에게 영향을 끼친다는 점이 다름

 

탑 다운(Top-Down) vs 바텀 업(Bottom-Up)

  • 탑다운(Top-Down)
    • 메모이제이션, 하향식
    • 큰 문제를 해결하기 위해 작은 문제를 호출
  • 바텀업 (Bottom-Up)
    • 상향식
    • 다이나믹 프로그래밍의 전형적인 형태
    • 작은 문제부터 차근차근 답을 도출
    • DP 테이블: 바텀업 방식에서 사용되는 결과 저장용 리스트

 

  • 다이나믹 프로그래밍의 유형임을 파악하는 것이 우선
    • 그리디, 구현, 완전 탐색 등의 아이디어로 문제를 해결할 수 있는지 검토
      • 완전 탐색 알고리즘으로 접근할 때 시간이 너무 오래걸리는 경우
        • 다이나믹 프로그래밍 적용 고려
        • 해결하고자 하는 부분 문제들의 중복 여부 확인
    • 재귀 함수로 구현 후 작은 문제에서 구한 답이 큰 문제에서도 사용되는지 확인
      • 메모이제이션이 사용 가능하다면 코드 개선
    • 보텀업 방식으로 구현하기

 

문제

정수 삼각형

1932번: 정수 삼각형

import sys
input = sys.stdin.readline

n = int(input())
triangle = [list(map(int, input().split())) for _ in range(n)]

for i in range(1, n):
    for j in range(i + 1):
        if j == 0:
            left = 0
        else:
            left = triangle[i-1][j-1]

        if j == i:
            right = 0
        else:
            right = triangle[i-1][j]
        triangle[i][j] += max(left, right)

print(max(triangle[n-1]))

 

퇴사

14501번: 퇴사

import sys
input = sys.stdin.readline

n = int(input())
table = [list(map(int, input().split())) for _ in range(n)]

dp = [0] * (n+1)
answer = 0

for i in range(n - 1, -1, -1):
    if table[i][0] + i <= n:
        dp[i] = max(table[i][1] + dp[table[i][0] + i], answer)
        answer = dp[i]
    else:
        dp[i] = answer

print(answer)

 

병사 배치하기

18353번: 병사 배치하기

import sys
input = sys.stdin.readline

n = int(input())
fights = list(map(int, input().split()))
fights.reverse()

dp = [1] * n

for i in range(1, n):
    for j in range(i):
        if fights[i] > fights[j]:
            dp[i] = max(dp[i], dp[j] + 1)

print(n - max(dp))

 

가장 긴 증가하는 부분 수열

11053번: 가장 긴 증가하는 부분 수열

import sys

N = int(sys.stdin.readline())
A = list(map(int, input().split()))
dp = [1] * N

for i in range(1, N):
    for j in range(i):
        if A[i] > A[j]:
            dp[i] = max(dp[i], dp[j]+1)

print(max(dp))

 

계단 오르기

2579번: 계단 오르기

import sys
input = sys.stdin.readline

n = int(input())
stairs = [0] * 301
for i in range(1, n+1):
    stairs[i] = int(input())
dp = [0] * 301

dp[1] = stairs[1]
dp[2] = stairs[1] + stairs[2]
dp[3] = max(stairs[1] + stairs[3], stairs[2] + stairs[3])

if n >= 4:
    for i in range(4, n+1):
        dp[i] = max(dp[i-3] + stairs[i-1] + stairs[i], dp[i-2] + stairs[i])

print(dp[n])

 

징검다리 건너기

22869번: 징검다리 건너기 (small)

import sys
input = sys.stdin.readline
INF = int(1e9)

n, k = map(int, input().split())
nums = list(map(int, input().split()))

dp = [INF] * n
dp[0] = 0

for i in range(n-1):
    if dp[i] > k:
        continue
    for j in range(i+1, n):
        dp[j] = min(dp[j], (j-i)*(1 + abs(nums[j]-nums[i])))

if dp[-1] <= k:
    print("YES")
else:
    print("NO")

길이를 구할 때는 INF도 적극적으로 활용

반응형
profile

다라다라V

@DaraDaraV

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!