elevne's Study Note
Python 알고리즘 공부 (7: 다이나믹 프로그래밍) 본문
다이나믹 프로그래밍, 동적 프로그래밍은 연산 속도와 메모리 공간을 최대한으로 활용할 수 있게끔 해주는 효율적인 알고리즘이다. 다이나믹 프로그래밍으로 해결할 수 있는 대표적인 문제로 피보나치 수열 문제가 있다. 수학자들은 점화식을 통해 수열의 항이 이어지는 형태를 간결하게 표현한다.
피보나치 점화식은 인접 3 항 간 점화식이다. 이러한 점화식에 따라 실제로 피보나치를 구하는 함수를 작성하면, 재귀함수를 작성해볼 수 있다. 하지만 재귀함수를 사용하면, f(n) 함수에서 n 의 값이 커질수록 수행 시간이 기하급수적으로 늘어나게 된다. ( n 이 30 일 때, 약 10 억 가량의 연산을 수행한다) 재귀함수를 사용하는 것보다는, 다이나믹 프로그래밍을 사용하면 효율적으로 문제를 해결할 수 있다. 아래 조건들이 만족될 때, 다이나믹 프로그래밍을 사용할 수 있다.
- 큰 문제를 작은 문제로 나눌 수 있다
- 작은 문제에서 구한 정답은 그것을 포함하는 큰 문제에서도 동일하다
피보나치 수열은 이러한 조건을 만족하는 대표 문제로, 메모이제이션 기법을 사용하여 해결할 수 있다. 메모이제이션은 다이나믹 프로그래밍을 구현하는 방법 중 하나로, 한 번 구한 결과를 메모리 공간에 메모해두고 같은 식을 다시 호출하면 메모한 결과를 그대로 가져오는 기법이다. (캐싱이라고도 한다)
d = [0] * 100
def fibo(x):
print("f(" + str(x) + ")", end=" ")
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]
fibo(30)
위와 같은 코드를 사용하면, 이미 해결된 문제에 대해서는 다시 해결하지 않는다. 이처럼 재귀함수를 이용하여 다이나믹 프로그래밍 소스코드를 작성하는 방법을, 큰 문제를 해결하기 위해 작은 문제를 호출한다고 하여 Top-Down 방식이라고 말한다. 반면, 단순히 반복문을 이용하여 소스코드를 작성하는 경우 작은 문제부터 차근차근 답을 도출한다고 하여 Bottom-Up 방식이라고 한다. Bottom-Up 방식으로 푸는 코드는 아래와 같다.
def bottom_up():
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])
문제 1. 1 로 만들기
정수 X가 주어질때 정수 X에 사용할 수 있는 연산은 다음과 같이 4가지이다.
1) X가 5로 나누어떨어지면, 5로 나눈다.
2) X가 3으로 나누어 떨어지면, 3으로 나눈다.
3) X가 2로 나누어 떨어지면, 2로 나눈다.
4) X에서 1을 뺀다.
정수 X가 주어졌을때, 연산 4개를 적절히 사용해서 1을 만들어야한다. 이 연산을 사용하는 횟수의 최솟값을 출력해라.
X = 26일 경우
1. 26 - 1 = 25
2. 25 /5 = 5
3. 5 / 5 = 1
입력
첫째 줄에 정수 X이 주어진다. (1<=X<=30,000)
출력
첫째 줄에 연산을 하는 횟수의 최솟값을 출력한다.
위 문제도 잘 알려진 다이나믹 프로그래밍 문제라고 한다. (함수가 호출되는 과정을 그림으로 그려보면 이해하는데 도움이 된다)
def prob1():
x = int(input())
d = [0] * 30001
for i in range(2, x + 1):
d[i] = d[i-1] + 1
if i % 2 == 0:
d[i] = min(d[i], d[i//2] + 1)
if i % 3 == 0:
d[i] = min(d[i], d[i // 3] + 1)
if i % 5 == 0:
d[i] = min(d[i], d[i // 5] + 1)
print(d[x])
문제 2. 개미 전사
개미전사는 부족한 식량을 충당하고자 메뚜기 마을의 식량창고를 몰래 공격하려고 한다. 메뚜기 마을에는 여러 개의 식량창고가 있는데 식량창고는 일직선으로 이어져 있다. 각 식량창고에는 정해진 수의 식량을 저장하고 있ㄷ으며 개미 전사는 식량창고를 선택적으로 약탈하여 식량을 빼앗을 예정이다. 이때 메뚜기 정찰병들은 일직선상에 존재하는 식량창고 중에서 서로 인접한 식량창고가 공격받으면 바로 알아챌 수 있다. 따라서 개미 전사가 정찰병에게 들키지 않고 식량창고를 약탈하기 위해서는 최소한 한 칸 이상 떨어진 식량창고를 약탈해야 한다. 예를 들어 식량창고 4개가 다음과 같이 존재한다고 가정하자.
{1, 3, 1, 5}
이때 개미 전사는 두 번째 식량창고와 네 번째 식량창고를 선택했을 때 최댓값인 총 8개의 식량을 빼앗을 수 있다. 개미 전사는 식량창고가 이렇게 일직선상일 때 최대한 많은 식량을 얻기를 원한다.
개미 전사를 위해 식량창고 N개에 대한 정보가 주어졌을 때 얻을 수 있는 식량의 최댓값을 구하는 프로그램을 작성하시오.
입력
첫째 줄에 식량창고의 개수 N이 주어진다. (3<=N<=100)
둘째 줄에 공백으로 구분되어 각 식량창고에 저장된 식량의 개수 K가 주어진다. (0<=K<=1,000)
출력
첫째 줄에 개미 전사가 얻을 수 있는 식량의 최댓값을 출력하시오.
def prob2():
n = int(input())
array = list(map(int, input().split()))
d = [0] * 100
d[0] = array[0]
d[1] = max(array[0], array[1])
for i in range(2, n):
d[i] = max(d[i-1], d[i-2] + array[i])
print(d[n-1])
문제 3. 바닥 공사
문제가로의 길이가 N, 세로의 길이가 2인 직사각형 형태의 얇은 바닥이 있다.
태일이는 이 얇은 바닥을 1 X 2의 덮개, 2 X 1의 덮개, 2 X 2의 덮개를 이용해 채우고자 한다.
이 때 바닥을 채우는 모든 경우의 수를 구하는 프로그램을 작성하시오.
입력
첫째 줄에 N이 주어진다. (1 ≤ N ≤ 1,000)
출력
첫째 줄에 N이 1이 될 때까지 1번 혹은 2번의 과정을 수행해야 하는 최솟값을 출력한다.첫째 줄에 2 X N 크기의 바닥을 채우는 방법의 수를 796,796으로 나눈 나머지를 출력한다.
def prob3():
n = int(input())
d = [0] * 1001
d[1] = 1
d[2] = 3
for i in range(3, n+1):
d[i] = (d[i-1] + 2 * d[i-2]) % 796796
print(d[n])
문제 4. 효율적인 화폐 구성
N가지 종류의 화폐가 있다. 이 화폐들의 개수를 최소한으로 이용해서 그 가치의 합이 M원이 되도록 하려고 한다. 이때 각 화폐는 몇 개라도 사용할 수 있으며, 사용한 화폐의 구성은 같지만 순서만 다른 것은 같은 경우로 구분한다. 예를 들어 2원, 3원 단위의 화폐가 있을 때는 15원을 만들기 위해 3원을 5개 사용하는 것이 가장 최소한의 화폐 개수이다.
입력
첫째 줄에 N,M이 주어진다(1<= N <= 100, 1<= M <= 10,000)
이후의 N개의 줄에는 각 화폐의 가치가 주어진다. 화폐의 가치는 10,000보다 작거나 같은 자연수이다.
출력
첫째 줄에 경우의 수 X를 출력한다.(불가능할 때는 -1을 출력한다)
def prob4():
n, m = map(int, input().split())
array = []
for i in range(n):
array.append(int(input()))
d = [10001] * (m+1)
d[0] = 0
for i in range(n):
for j in range(array[i], m+1):
if d[j-array[i]] != 10001:
d[j] = min(d[j], d[j-array[i]]+1)
if d[m] == 10001:
print(-1)
else:
print(d[m])
Reference:
이것이 취업을 위한 코딩 테스트다
'Backend > Algorithm' 카테고리의 다른 글
Python 알고리즘 공부 (8: 최단경로) (0) | 2023.07.22 |
---|---|
Python 알고리즘 공부 (6: 이진탐색) (0) | 2023.01.20 |
Python 알고리즘 공부 (5: 정렬) (0) | 2023.01.13 |
Python 알고리즘 공부 (4: DFS/BFS) (0) | 2023.01.08 |
Python 알고리즘 공부 (3: 구현) (0) | 2023.01.04 |