호기심 많은 분석가
[이것이 취업을 위한 코딩 테스트다 with 파이썬] (한빛미디어, 나동빈) Chapter8(2). 다이나믹 프로그래밍 본문
[이것이 취업을 위한 코딩 테스트다 with 파이썬] (한빛미디어, 나동빈) Chapter8(2). 다이나믹 프로그래밍
DA Hun 2021. 5. 25. 14:45포스팅 개요
'혹시나 책에 있을 모든 실수와 오류는 온전히 제 책임이며, 책에 실린 좋은 아이디어와 표현은 모두 리뷰어님들의 조언 덕분입니다. 정말 고맙습니다.'라는 지은이의 글은 나동빈 저자님의 인품을 느낄 수 있는 한 줄이었습니다.
저도 저런 마인드를 가진 사람이 되겠다고 다짐하며 책과의 여정을 떠나보겠습니다.
포스팅 본문
저번 포스팅에서는 다이나믹 프로그래밍에 대해 알아보았습니다. 2021.05.25 - [Coding Test & Algorithm] - [이것이 취업을 위한 코딩 테스트다 with 파이썬] (한빛미디어, 나동빈) Chapter8(1). 다이나믹 프로그래밍
이번 포스팅에서는 그 개념을 활용하여 예제를 해결해보겠습니다.
본 코드는 모두 제 Github에 올려두었습니다. (https://github.com/herjh0405/Coding_Test)
8-5. 1로 만들기
정수 X가 주어질 때 정수 X에 사용할 수 있는 연산은 다음과 같이 4가지이다.
- X가 5로 나누어떨어지면, 5로 나눈다.
- X가 3으로 나누어떨어지면, 3으로 나눈다.
- X가 2로 나누어떨어지면, 2로 나눈다.
- X에서 1을 뺀다.입력조건. 첫째 줄에 정수 X가 주어진다. (1 <= x <= 30000)
- 정수 X가 주어졌을 때, 연산 4개를 적절히 사용해서 1을 만들려고 한다. 연산을 사용하는 횟수의 최솟값을 출력하시오.
# 정수 x를 입력받기
x = int(input())
# 앞서 계산된 결과를 저장하기 위한 DP 테이블 초기화
d = [0] * 30001
# 다이나믹 프로그래밍 진행(바텀업)
for i in range(2, x+1) :
# 현재의 수에서 1을 빼는 경우
d[i] = d[i-1] + 1
# 현재의 수가 2로 나누어 떨어지는 경우
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])
문제 해설
문제를 도식화해보면 피보나치와 같이 동일한 함수에서 구하는 값들이 동일해야 함을 알 수 있다.
문제가 요구하는 것을 점화식으로 표현해보자. 점화식 끝에 1을 더해주는 이유는 함수의 호출 횟수를 구해야 하기 때문이다.
$$ A_i = min(A_{i-1}, A_{i/2}, A_{i/3}, A_{i/5}) +1 $$
실제 코드로 구현할 때는 1을 빼는 연산을 제외하고는 해당 수로 나누어떨어질 때에 한해서만 점화식을 적용할 수 있다. 더불어 두 수 중에서 단순히 더 작은 수를 구하고자 할 대는 파이썬에서의 min() 함수를 이용하면 간단하다.
점화식을 잘 세우면 문제를 쉽게 해결하는 데 도움이 된다. 점화식을 세우는 것은 예전부터 많이 해봤기에 천천히 접근하면 될 것 같다. 한번 풀어봤기에 앞으로도 풀 수 있을 것 같고, 모르고 만났다면 굉장히 당황했지 않았을까.
8-6. 개미 전사
개미 전사는 부족한 식량을 충당하고자 메뚜기 마을의 식량창고를 몰래 공격하려고 한다. 메뚜기 마을에는 여러 개의 식량창고가 있는데 식량창고는 일직선으로 이어져 있다. 각 식량창고에는 정해진 수의 식량을 저장하고 있으며 개미 전사는 식량창고를 선택적으로 약탈하여 식량을 빼앗을 예정이다. 이때 메뚜기 정찰병들은 일직선상에 존재하는 식량창고 중에서 서로 인접한 식량창고가 공격받으면 바로 알아챌 수 있다. 따라서 개미 전사가 정찰병에게 들키지 않고 식량창고를 약탈하기 위해서는 최소한 한 칸 이상 떨어진 식량창고를 약탈해야 한다.
개미 전사를 위해 식량 창고 N개에 대한 정보가 주어졌을 때 얻을 수 있는 식량의 최댓값을 구하는 프로그램을 작성하시오.
입력 조건
- 첫째 줄에 식량창고의 개수 N이 주어진다.(3 <=N <=100)
- 둘째 줄에 공백으로 구분되어 각 식량창고에 저장된 식량의 개수 K가 주어진다.(0 <=k <=1000)
import sys
# 정수 N을 입력받기
n = int(input())
# 모든 식량 정보 입력받기
fd = list(map(int, sys.stdin.readline().split()))
# 점화식 $$ A_i = max(A_{i-1}, A_{i-2}+k_i) $$
# 앞서 계산된 결과를 저장하기 위한 DP 테이블 초기화
d = [0] * n
# 다이나믹 프로그래밍 진행(바텀업)
d[0] = fd[0]
d[1] = max(fd[0], fd[1])
for i in range(2, n) :
d[i] = max(d[i-1], d[i-2]+fd[i])
# 계산된 결과 출력
print(d[n-1])
8-7. 바닥 공사
가로의 길이가 N, 세로의 길이가 2인 직사각형 형태의 얇은 바닥이 있다.
태일이는 이 얇은 바닥을 1X2의 덮개, 2X1의 덮개, 2X2의 덮개를 이용해 채우고자 한다.
이때 바닥을 채우는 모든 경우의 수를 구하는 프로그램을 작성하시오.
입력 조건. 첫째 줄에 N이 주어진다. (1 <=N <=1000)
출력 조건. 첫째 줄에 2XN 크기의 바닥을 채우는 방법의 수를 796,796으로 나눈 나머지를 출력한다.
n = int(input())
d = [0] * 1001
d[0] = 1
d[1] = 3
for i in range(2, n+1) :
d[i] = (d[i-1] + 2*d[i-2])%796796
print(d[n-1])
DP 문제임을 파악하면 점화식을 잘 세우기만 하면 간단히 해결할 수 있다. 수학 문제 푸는 기분이라 신난다.
8-8. 효율적인 화폐 구성
N가지 종류의 화폐가 있다. 이 화폐들의 개수를 최소한으로 이용해서 그 가치의 합이 M원이 되도록 하려고 한다.
이때 각 화폐는 몇 개라도 사용할 수 있으며, 사용한 화폐의 구성은 같지만 순서가 다른 것은 같은 경우로 구분한다.
입력 조건
- 첫째 줄에 N, M이 주어진다. (1 <=N <=100, 1 <=M <=10000)
- 이후의 N개의 줄에는 각 화폐의 가치가 주어진다. 화폐의 가치는 10000보다 작거나 같은 자연수이다.
출력 조건
- 첫째 줄에 경우의 수 X를 출력한다. 불가능할 때는 -1을 출력한다.
import sys
n, m = map(int, input().split())
arr_val = []
for _ in range(n) :
arr_val.append(int(sys.stdin.readline()))
d = [10001] * (m+1)
d[0] = 0
for i in range(n) :
for j in range(arr_val[i], m+1) :
if d[j-arr_val[i]] != 100001 : # (i-k)원을 만드는 방법이 존재하는 경우
d[j] = min(d[j], d[j-arr_val[i]]+1)
if d[m] == 10001 : # 최종적으로 M원을 만드는 방법이 없는 경우
print(-1)
else :
print(d[m])
문제 해설
금액 i를 만들 수 있는 최소한의 화폐 개수를 Ai, 화폐의 단위를 k라고 했을 때, 다음과 같은 점화식을 작성할 수 있다. $ A_{i-k} $는 금액 (i-k)를 만들 수 있는 최소한의 화폐 개수를 의미한다.
- $ A_{i-k}를 만드는 방법이 존재하는 경우, A_i = min(A_{i}, A_{i-k}+1) $
- $ A_{i-k}를 만드는 방법이 존재하지 않는 경우, A_i= 10001 $
이번 문제는 다이나믹 프로그래밍 기법으로 풀어야함을 앎에도 불구하고 굉장히 고민이 많이 됐다. 점화식을 세우는 것부터 그것을 코드로 옮기기까지 꽤 많은 시간을 들여야했다. 다음번에 다시 풀어봐야겠다.
다이나믹 프로그래밍 기법은 고등학교 때의 수열처럼 풀면 풀수록 빠르게 적응할 듯하다. 이렇게 Chapter8을 마무리해보겠습니다.
Chapter9에서 뵙겠습니다. :)
'Coding > Coding Test & Algorithm' 카테고리의 다른 글
[Python] 입력 받기 (sys.stdin.readline) (7) | 2021.05.27 |
---|---|
[백준 10951] A+B - 4 (Python) (0) | 2021.05.25 |
[이것이 취업을 위한 코딩 테스트다 with 파이썬] (한빛미디어, 나동빈) Chapter8(1). 다이나믹 프로그래밍 (4) | 2021.05.25 |
[이것이 취업을 위한 코딩 테스트다 with 파이썬] (한빛미디어, 나동빈) Chapter7. 이진 탐색 (2) | 2021.05.22 |
[이것이 취업을 위한 코딩 테스트다 with 파이썬] (한빛미디어, 나동빈) Chapter6(2). 정렬 (1) | 2021.05.21 |