- 양의 정수 n의 합 표현 방법(순서고려)
- 양의 정수 n의 합 표현 방법(순서 X)
- 거스름 돈 나누어 주는 방법
계단을 오를 때, 한 번에 한 개 혹은 두 개만 계단을 오를 수 있다. n개의 계단 아래에서 계단 꼭대기까지 올라가는 방법의 수를 구하시오
ex. 4개의 계단을 올라갈 수 있는 방법 = 4를 1과 2의 합으로 나타내는 방법과 동일
C(i) : i개의 계단 아래에서 꼭대기까지 올라가는 방법의 수
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | ... |
---|---|---|---|---|---|---|---|---|
C[i] | 1 | 1 | 2 | 3 | 5 | 8 | 13 | ... |
def count(n):
C = [0 for i in range(n+1)]
C[0] = C[1] = 1
for i in range(2, n+1):
C[i] = C[i-1] + C[i-2]
return C[n]
주요 연산 : C[i] = C[i-1] + C[i-2]
수행시간 : O(N)
++ 참고 : 2xN 타일링에서도 똑같이 동적 계획법으로 풀 수 있다.
백준알고리즘 1793번 문제 바로가기
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | ... |
---|---|---|---|---|---|---|---|---|
C[i] | 1 | 1 | 1 | 2 | 4 | 6 | 9 | ... |
def count(n):
C = [0 for i in range(n+1)]
C[0] = C[1] = C[2] = 1
C[3] = 2
for i in range(4, n+1):
C[i] = C[i-1] + C[i-3] + C[i-4]
return C[n]
주요 연산 : C[i] = C[i-1] + C[i-3] + C[i-4]
수행시간 : O(N)
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | ... |
---|---|---|---|---|---|---|---|---|
C[i] | 1 | 1 | 1 | 2 | 4 | 6 | 9 | ... |
# numList[i] = ni+1
def count(n, numList):
C = [0 for i in range(n+1)]
C[0] = 1
for i in range(numList[0], n+1):
for x in numList:
if i >= x:
C[i] += C[i-x]
else:
break
return C[n]
수행시간 : O(N*K)
(K가 상수가 아닐 수 있다.)
양의 정수 n에 대하여, n을 1부터 n까지 숫자들의 합으로 나타내는 방법의 수를 구하시오. (순서 구분)
ex. n=4인 경우 다음의 8가지가 있다. (마지막에 오는 숫자를 기준으로 구분)
C(i) : i를 1부터 i까지의 숫자들의 합으로 나타내는 방법의 수
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | ... |
---|---|---|---|---|---|---|---|---|
C[i] | 1 | 1 | 2 | 4 | 8 | 16 | 32 | ... |
def count(n):
C = [0 for i in range(n+1)]
C[0] = 1
for i in range(1, n+1):
for j in range(i):
C[i] += C[j]
return C[n]
수행시간 : O(N^2)
: (1+2+3+ ... + n) = n*(n+1)/2
재귀 식을 잘 분석하면 C(n) = 2^(n-1) 이다.
(그냥 계산하면 C(7) = 64 니까)
양의 정수 n에 대하여 n을 1부터 k까지 숫자들의 합으로 나타내는 방법의 수를 구하시오. (나열하는 숫자들의 순서를 고려)
ex. n = 4, k = 2인 경우 다음의 5가지가 있다.
C(i) : i를 1부터 k까지의 숫자들의 합으로 나타내는 방법의 수
i = 4, k = 2 (i ≥ k)
C(4) = C(3) + C(2)
---
i = 4, k = 5 (i < k)
C(4) = C(3) + C(2) + C(1) + C(0)
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | ... |
---|---|---|---|---|---|---|---|---|
C[i] | 1 | 1 | 2 | 4 | 7 | 13 | 24 | ... |
def count(n, k):
C = [0 for i in range(n+1)]
C[0] = 1
for i in range(1, n+1):
for j in range(min(n+1, k+1)): # k가 n보다 클 경우를 대비
if i >= j:
C[i] += C[i-j]
else:
break
return C[n]
수행시간 : O(N * k)
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|---|
C[i] | 0 | 2 | 7(=2+5) | 13 | 10 | 8(=2+6) | 10(=7+3) | ... |
P[i] | 0 | 0 | 1 | 0 | 0 | 1 | 2 | 6 |
P[i] : 이전에 어떤 계단을 밟고 왔는지를 기록.
C = [0 for i in range(n+1)]
# costs = [2, 5, 13, 10, 6, 3, 2]
# k_list = [1, 3, 4]
C[0] = 0
C[1] = C[0] + costs[0] # costs는 인덱스 0부터 시작!
C[2] = C[1] + costs[1]
C[3] = costs[2]
C[4] = costs[3]
for i in range(k_list[-1], n+1):
C[i] = min(C[i-1], C[i-3], C[i-4]) + costs[i-1]
return C[n]
시간 복잡도 : O(N)
양의 정수 n에 대하여, n을 1부터 n까지 숫자들의 합으로 나타내는 방법의 수를 구하시오. 단 나열되는 숫자들의 순서는 고려하지 않는다.
(1+2와 2+1은 동일한 것으로 간주한다)
ex. n=4인 경우 다음의 5가지 경우가 존재한다.
숫자들의 합에서 숫자들의 순서는 고려하지 않으므로, 숫자들의 합 표현은 증가하는 숫자들의 합으로 표현
C(i, j) : i를 1부터 j까지 숫자들의 합으로 나타내는 방법의 수
(나열되는 숫자와 순서는 고려하지 않음)
C(i, j) = 1 (if i = 0)
C(i, j) = C(i, i) (if i < j)
C(i, j) = C(i-j, j) + C(i, j-1) (if i ≥ j) // 숫자들 합의 표현에서 마지막 숫자가 j
(j를 사용하는 경우와 j를 사용하지 않는 경우로 분리해서 봄)
=> C(n, n)을 구하면 된다.
def count(n, k):
C = [[0 for j in range(n+1)]for i in range(n+1)]
for i in range(n+1):
for j in range(n+1):
if j == 1: # i를 1로 표현하는 방법의 수는 무조건 1
C[i][j] = 1
elif i == 1: # 1을 1부터 j까지의 수로 표현하는 방법의 수는 무조건 1
C[i][j] = 1
elif i < j: # 이 때 j는 i까지만 표현이 가능함
C[i][j] = C[i][i]
else: # i ≥ j, j를 포함하는 경우 + j를 포함하지 않는 경우
C[i][j] = C[i-j][j] + C[i, j-1]
return C[n][n]
동전들의 단위 c1, c2, ..., cn이 있다. 이들 동전들을 이용하여 거스름돈 M을 나누어주는 방법의 수를 구하시오.
ex. n = 3이고, (c1, c2, c3) = (1, 3, 5), M = 10인 경우 다음의 7가지 방법이 있다.
c1 < c2 < c3 < ... < cn이라 가정한다.
수행시간 : O(M*N)
numList = [0, 1, 3, 5]
def count(n, m, numList): # n : 거스름돈 개수, m : 거슬러 줘야하는 총 금액
C = [[0 for j in range(n+1)] for i in range(m+1)]
for i in range(m+1):
for j in range(n+1): # i = 5, j = 0, 1, 2, 3
# C[i][j] : 거스름 돈 i를 c1 ~ cj까지 동전들을 이용해서 나눠주는 방법의 수
if j == 0:
C[i][j] = 0
elif j > 0 and i == 0:
# 0으로 두면 곤란, 다른 수 이용할 때 쓰이기 때문
# 그냥 0원을 거슬러 주는 방법이 0개가 아닌 1개라고 생각하기
C[i][j] = 1
elif j == 1 and i < numList[1]:
# 동전의 최솟값보다 i가 더 작은 경우
C[i][j] = 0
elif i < numList[j]:
# 마지막 동전의 값이 구하려는 값보다 클 때는
# 마지막 동전 제외시키기
C[i][j] = C[i][j-1]
else:
x = numList[j] # 마지막 동전을 제외시킬 변수 x 선언
C[i][j] = C[i-x][j] + C[i][j-1]
print(C)
return C[m][n]
print(count(3, 10, numList))
++ 별첨
def findPath(n, k):
C = [[0 for i in range(n+1)] for j in range(n+1)]
for i in range(n+1):
for j in range(n+1):
if i == 0 or j == 0:
C[i][j] = 1
else:
C[i][j] = C[i][j-1] + C[i-1][j]
print(C)
return C[n][k]
print(findPath(5, 5))
[1, 1, 1, 1, 1, 1],
[1, 2, 3, 4, 5, 6],
[1, 3, 6, 10, 15, 21],
[1, 4, 10, 20, 35, 56],
[1, 5, 15, 35, 70, 126],
[1, 6, 21, 56, 126, 252]]