🤔 문제 설명
fibonacci(3)을 호출하면 다음과 같은 일이 일어난다.
fibonacci(3)은 fibonacci(2)와 fibonacci(1) (첫 번째 호출)을 호출한다.
fibonacci(2)는 fibonacci(1) (두 번째 호출)과 fibonacci(0)을 호출한다.
두 번째 호출한 fibonacci(1)은 1을 출력하고 1을 리턴한다.
fibonacci(0)은 0을 출력하고, 0을 리턴한다.
fibonacci(2)는 fibonacci(1)과 fibonacci(0)의 결과를 얻고, 1을 리턴한다.
첫 번째 호출한 fibonacci(1)은 1을 출력하고, 1을 리턴한다.
fibonacci(3)은 fibonacci(2)와 fibonacci(1)의 결과를 얻고, 2를 리턴한다.
1은 2번 출력되고, 0은 1번 출력된다. N이 주어졌을 때, fibonacci(N)을 호출했을 때, 0과 1이 각각 몇 번 출력되는지 구하는 프로그램을 작성하시오.
🤨 제한 사항
- 첫째 줄에 테스트 케이스의 개수 T가 주어진다.
- 각 테스트 케이스는 한 줄로 이루어져 있고, N이 주어진다. N은 40보다 작거나 같은 자연수 또는 0이다.
😀 입출력 예
입력 | 출력 |
3 0 1 3 |
1 0 0 1 1 2 |
👩🔧 사용 메서드 및 속성
sys.stdin.readline() | 사용자로부터 한 줄의 입력을 받습니다. |
split() | 문자열을 나눠서 배열로 반환합니다. |
append() | 리스트 끝에 요소를 추가합니다. |
👩🏫 어떻게 풀어요?
가끔 백준 문제 풀다보면 거슬리는 문제가 있지 않나요?
이 피보나치 문제가 그런 것인데, 하필 예제를 fibo(0), fibo(1), fibo(3)일 때로 넣어놔서 푸는 사람으로 하여금 "0" 과 "1"이 몇번 출력되는지 착각을 일으키게 합니다. 그래서 처음에는 "아니 뭐 이런 걸 문제로 내는거지?? 0은 한번이고 1은 1번 아니면 2번 밖에 안나올텐데" 라는 생각을 했습니다.....
물론 당연하게도 그런 문제는 아닙니다. 이 문제는 동적 프로그래밍 기법을 이용해야지만 시간을 단축할 수 있는 문제입니다. 저 같은 경우에는 저 0과 1을 글로벌 변수로 선언해서 하나하나씩 다 더한 다음에 memo에 넣는 방법을 시도하려고 했다가 노트에 피보나치 수열을 그려보며 규칙성을 찾고, 코드를 전면 수정했습니다.
피보나치 수열은 0과 1을 제외하고, 그 외의 값은 전값과 전전값의 덧셈으로 구할 수 있는 수열입니다.
0, 1, 1, 2, 3, 5 .... 이런식으로요.
그걸 이 문제처럼 그래프로 표현하고 표현식으로 나타내면
fib(0) = 0이 1개, 1이 0개니까 [ 1, 0 ]
fib(1) = 0이 0개, 1이 1개니까 [ 0, 1 ]
fib(2) = 0이 1개, 1이 1개니까 [ 1, 1 ]
fib(3) = 0이 1개, 1이 2개니까 [ 1, 2 ]
fib(4) = 0이 2개, 1이 3개니까 [ 2, 3 ]
fib(5) = 0이 3개, 1이 5개니까 [ 3, 5 ]
이렇게 나오는 걸 볼 수 있습니다.
혹시 규칙성이 있는것을 눈치채셨나요?
1의 개수는 전값과 전전값의 덧셈과 같고, 0의 개수는 전값의 1의 개수와 같다는 사실!
fib(5) = fib(4) + fib(3) = 5이고, 0의 개수는 fib(4)의 1의 개수와 같네요!!
그렇다면 문제는 쉽게 해결할 수 있겠네요.
동적 프로그래밍 기법을 사용해 봅시다.
memo[] (메모이제이션)를 선언해주고 거기다가 미리 0과 1의 결과값을 저장해줍시다. 그 다음 하나의 fib()가 종료될 때 값을 저장해서 넣어주면, 다음에 같은 fib()를 진행할 때는 굳이 깊게 재귀를 하지 않아도 결과가 나오겠죠?
👾트리스티의 답
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
import sys
n = int(sys.stdin.readline().split()[0])
arr = []
memo = {0 : 0, 1 : 1}
def fibonacci(number) :
global memo
if number in memo :
return memo[number]
fib = fibonacci(number - 1) + fibonacci(number - 2)
memo[number] = fib
return fib
for _ in range(n) :
cnt = int(sys.stdin.readline().split()[0])
if cnt == 0 :
arr.append([1, 0])
else:
arr.append([fibonacci(cnt - 1), fibonacci(cnt)])
for i in arr :
print(i[0], i[1])
|
cs |
※ 잘못된 정보가 있거나 수정사항이 있다면 댓글로 남겨주세요!
'Python > [백준] 문제 풀기' 카테고리의 다른 글
[10869] 사칙연산 (0) | 2021.03.14 |
---|---|
[1914] 하노이 탑 (0) | 2021.03.11 |
[7576] 토마토 (0) | 2021.03.11 |
[11053] 가장 긴 증가하는 부분 수열 (0) | 2021.03.11 |
[1단계] 두 개 뽑아서 더하기 (0) | 2021.02.26 |