본문 바로가기

알고리즘

코테 준비를 위한 DP ( Dynamic Programming ) feat. 몇몇 백준 문제

 

서론 


 

주변에 취업을 하신 지인 분이나 코딩테스트를 몇 번 보신 분들이 필수적으로 코테 알고리즘에서 중요하다고 했던 것들 중에서 바로 동적 프로그래밍을 다룰 것이다.

 

내 시기는 지금 개발 공부를 더 열심히하고 프로젝트도 많이 해보는 경험을 쌓는 시기라고 많이 느낀다.

 

그래서 요새는 알고리즘보다는 그냥 개발 공부를 더 한다.

 

하지만 놓아야 해도 놓을 수가 없는게 나는 나중에 코딩 테스트를 잘 보고 싶은 욕구가 크기 때문에 

 

그냥 닥치는대로 푸는 것이 아닌 알고리즘을 하나 하나 풀어가면서 푸는 방식을 알아가면서

 

정리만 하고 개발 공부에 집중하려고 한다.

 

이 DP 블로그는 1주일 간 3시간씩 투자하면서 정리하고 공부했던 일종의 일기? 라고 해야할까

 

이제 본론으로 들어가기 전에 DP를 공부하며 느낀 것은 규칙을 찾고 점화식을 구하는게 90% / 코딩 10% 라고 생각한다.

( 본론에서 나오는 Bottom-up 방식으로 모든 문제를 풀었음 )

 

내가 수학을 하는건지 코테를 준비하는건지 가끔 오락가락한다...

 

 

 

 

 

본론

 


 DP ( Dynamic programming) 란 무엇일까??  

( 진실 : 알고리즘 이름은 그냥 멋있어 보여서 지은 것이랍니다.. )

 

어떤 복잡하고 큰 문제를 쪼개어서 작은 문제들의 규칙성 혹은 결과들을 사용해서 다시 큰 문제로 돌아가서 해결하는 방법이다.

 

이 방법이 의미하는 것은 공간 복잡도를 더 늘려서 (작은 문제로 나눈다 )시간 복잡도를 단축시키는 방법( 큰 문제를 효율적으로 푼다 )

이라고 생각하면 된다.

 

작은 문제들이 풀린 결과들은 규칙성을 띄게 되면 다시 계속 사용하는 방식으로 진행이되는 방식.

 

즉 , 재귀적인 방향성도 존재하며 점화식으로 반복적으로 푸는 반복문 방식도 사용된다.

 


 

DP 의  방식 ?  TOP-DOWN  VS  BOTTOM-UP

 

Top - down ( 재귀 방식 )

 

큰 문제를 작은 문제로 나누어서 푸는 방식으로 함수를 사용해서 반복적으로 그 함수를 재귀하여 

문제를 푸는 방식이다. 대표적인 예로는 피보나치 함수가 있다.

 

장점 :

 

중복을 피하는 방식을 사용하고 필요 없는 값을 사용하지 않는다.

 

구현이 비교적 쉽게 사용 가능하다.

 

단점 : 

 

구현된 함수가 메모리를 감당하지 못해서 과부하가 일어날 수 있는 가능성이 크다.

 

작은 문제들을 제대로 활용하지 못할 경우 최적의 수 또는 경우의 수가 달라지는 경우가 발생한다.

 

 

Bottom - up ( 점화식 )

 

top -down의 방식은 큰 문제를 나누어서 푸는 방식이지만 이 방식은 작은 문제들을 하나 하나 해결해 나가며 푸는 방식이다.

이름을 직역으로 해석해보면 밑에서 부터 올라간다. 라는 형식이기 때문이다.

규칙을 찾고 점화식을 구하여 배열 , 리스트를 통해 결과를 저장하고 풀어가는 방식이다.

 

장점 :

 

직관적으로 이해하기 비교적 쉽다.

 

작은 문제부터 차례대로 풀기 때문에 최적의 해 보장이 된다.

 

메모리의 과부하가 일어나지 않는다.

 

단점 :

 

필요없는 값이나 중복된 값들을 계산한다.

 

결과를 계속 저장하면서 가기 때문에 메모리 사용이 커지는 ( 공간 복잡도 ) 일이 생긴다.

 

 

 

 

# 이렇게 방식을 설명했는데 실전에서는 " 이 친구는 DP 문제야 ~ " 라고 알려주진 않는다. 

 

그렇기 때문에 어떤 것이 DP 문제에 충족할까??  

 


 

이 친구가 DP 문제 일까요? 

 

내가 공부하면서 DP의 조건에는 총 3가지가 있었던거 같다.

 

1)  규칙성

 2) 최적의 해 구하기  

3) 중복성

 

 

1) 규칙성

 

 dp의 특성은 작은 문제들을 수기로 작성하여 풀 수 있으며 또한 규칙이 발생될 수 있다.이런 규칙을 통해 점화식을 만드는 것이 가능하다.

 

 

2) 최적의 해 구하기

 

dp에서 요구하는 것은 최적의 결과를 내는 것이나 작은 문제들을 주어주면서 경우의 수를 최고의 결과로 요구할 때 주로 사용되는 조건이 있다. 

 

3) 중복성 (중요)

 

아마 내가 생각한 조건 중에서 이 조건이 중요하지 않을까 싶다.

중복성은 예를 들어 어떤 문제의 N = 3 경우의 수를 구해!! 를 요구하고 N=2 경우의 수를 N=3경우의 수를 구할 때 사용하는 경우가 많다.

 

대표적인 또 다른 예로는 피보나치가 있다.

 

https://velog.io/@nodada/피보나치

 

중복성을 보면 f(3)은 그 전에 f(2)와 f(1)을 중복적으로 사용한다.

 

이런 조건 3가지가 나타나면 DP 문제이다.

 

 

 


 

 

DP는 많은 문제들을 풀어보고 예시들을 많이 겪어봐야 이해가 가는거 같다.

 

 

이제 마지막으로 내가 DP 공부를 하면서 풀었던 한 문제를 보며 설명하겠다.

 

 

https://www.acmicpc.net/problem/11727

 

 

 

 

 

 

 

대충 문제를 설명하면 2*1 ,1*2 와 2*2로 2*N의 사각형을 몇 개를 사용해서 만들 수 있는지를 묻는 문제이다.

 

나는 여기서 바로 키보드에 손을 대지 않고 바로 메모장을 열어서 몇 개가 나오는지 그리면서 숫자를 세어갔다.

 

사실 5개까지만 구했다.

 

그러고 느낀 것은 " 아 규칙성을 띄겠구나.. " 라는 생각이었다.

 

보통 2*2도 2*1과 1*2로 만들 수 있으니깐 2*2를 사용하는 빈도가 규칙적으로 바뀌겠지? 로 생각이 들어갔다.

 

그래서 이런 점화식이 나오게 되었다.

 

이렇게 1) 조건에 해당 되는 규칙성과 동시에 홀수와 짝수를 합친 최적의 해를 구하는 방식도 찾게되며 1) 조건2) 조건이 

 

동시에 찾게 된다.

 

이 문제를 풀 때 찾지 못하였지만 3) 중복성도 포함이 된다. 

 

예를 들면 2*3 에서 2*4를 만들 때 2*3의 경우를 사용이 가능하는 중복적인 조건을 찾을 수 있다.

 


 

그 밖에 코테 대비해서 추천 받은 DP 문제들 .. 

 

 

https://www.acmicpc.net/problem/2293

 

이 문제는 규칙을 찾기가 너무 힘들었음.. 코딩은 2분 생각은 2시간..

 

 

 

 

 

# 2293 동전 1 / DP

import sys

input = sys.stdin.readline

N, K = map(int, input().split())

arr = []

for _ in range(N):
    
    arr.append(int(input()))


coin = [0] * (K+1)


coin [0] = 1

for i in arr:
    for j in range(i, K+1):

        coin[j] += coin[j-i]


print(coin[K])

 

 

https://www.acmicpc.net/problem/15989

 

 

 

 

 

 

 

 

 

 

 

#15989 1,2,3 더하기 4 / DP

import sys

input = sys.stdin.readline

arr = [1] * 10001 # 1을 무조건 하나씩을 가지고 있으니깐 1을 설정해줌.

# 또한 N개가 2로 나뉘어지는 시점은 2이므로 2부터

for N in range(2,10001):

    arr[N] = 1+(N//2)


# +3이 시작되는 시점은 3부터 이므로 3부터 범위를 지정

for N in range(3,10001):

    arr[N] += arr[N-3]


count = int(input())

for i in range(count):

    print(arr[int(input())])

 

 

 

 

 

 

https://www.acmicpc.net/problem/1003

 

 

 

 

 

 

 

 

 

https://www.acmicpc.net/problem/9095

 

 

 


 

마무리


 

DP 는 진짜 그냥 수학인거 같고 모든 알고리즘이 다 그렇겠지만 문제를 많이 풀어봐야 하는 것 같다...

 

 

또 요새 개발 공부를 하고 있지만 정작 정리를 제대로 하지 않는 게으름을 제대로 나에게 표현 중이다...

 

 

다시 간이 프로젝트 및 공부를 더 해야겠다...

 

 

허나 !!  방학 때라도 하루에 한 개의 알고리즘 문제 풀어야지 ! ( 학원에서 알고리즘 가르쳐야해서 해야댐 )

 

 

마무리로 이제 개발 공부 정리도 올려야겠다. 너무 알고리즘만 올려...