문제
정수 4를 1, 2, 3의 합으로 나타내는 방법은 총 4가지가 있다. 합을 나타낼 때는 수를 1개 이상 사용해야 한다. 합을 이루고 있는 수의 순서만 다른 것은 같은 것으로 친다.
- 1+1+1+1
- 2+1+1 (1+1+2, 1+2+1)
- 2+2
- 1+3 (3+1)
정수 n이 주어졌을 때, n을 1, 2, 3의 합으로 나타내는 방법의 수를 구하는 프로그램을 작성하시오.
입력
첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고, 정수 n이 주어진다. n은 양수이며 10,000보다 작거나 같다.
출력
각 테스트 케이스마다, n을 1, 2, 3의 합으로 나타내는 방법의 수를 출력한다.
예제 입력 1
3
4
7
10
예제 출력 1
4
8
14
아이디어
먼저, 누가봐도 DP문제였다. 따라서 일반항을 찾아보았다. 그 과정은 다음과 같다.
각 경우에 대해서 3까지 사용하는 경우, 2까지만 사용하는 경우, 1로만 나타내는 경우를 생각해보았을때,
- 3까지 사용하는 경우 : a_(n-3)으로 나타낼 수 있음
- 2까지 사용하는 경우: n/2의 몫 부분으로 나타낼 수 있음
- 1까지 사용하는 경우: 단 1가지
이렇게 나눌 수 있었다. 각각 경우에 대해 모두 더해주면 위와 같은 일반항 식을 구할 수 있었고,
이를 코드로 표현해주었다.
추가적으로 메모이제이션기법을 사용해주었다. 메모이제이션은 이전에 계산한 값을 메모리에 저장하여 중복적인 계산을 제거하여 실행 속도를 빠르게 해주는 기법(이라고 한다 ㅎㅎ) 으로 DP의 핵심이다.
문제 풀이
'''
백준 15989번_1,2,3 더하기 4
'''
# 일반항 구하는 함수 정의
def general(n, memo):
if n <= 0:
return 0
if memo[n] != -1: # 중복 계산 제외시키기 (메모이제이션)
return memo[n]
for i in range(1, n + 1):
if i == 1:
memo[i] = 1
elif i == 2:
memo[i] = 2
elif i == 3:
memo[i] = 3
else:
memo[i] = memo[i - 3] + (i // 2) + 1
return memo[n]
t = int(input()) # 테스트 케이스의 개수
testCase = [] # 테스트 케이스 저장할 리스트 선언
answer = [] # 정답 담을 리스트 선언
# testCase 추가
for _ in range(t):
testCase.append(int(input()))
memo = [-1] * (max(testCase)+1)
# 1,2,3의 합 계산
for tc in testCase:
answer.append(general(tc,memo))
# 정답 출력
for a in answer:
print(a)
'코딩테스트 > 백준(Python)' 카테고리의 다른 글
[백준][Python] 3758번. KCPC(실버2) (0) | 2024.07.07 |
---|---|
[백준][Python] 20922번. 겹치는 건 싫어(실버1) (0) | 2024.07.06 |
[그리디][파이썬][백준] 13305번 주유소 (0) | 2023.03.30 |
[그리디][파이썬][백준] 1541번 잃어버린 괄호 (0) | 2023.03.30 |
[그리디][파이썬][백준]1931번 회의실배정 (0) | 2023.03.30 |