https://www.acmicpc.net/problem/1003
단순히 피보나치 수를 구하라는 문제는 아니다.
피보나치 수열은 점화식으로 정의ㅎㄹ 수 있는데
대개 점화식으로 표현된 수열의 일반항은 경계 조건과 함께 재귀 함수로 표현할 수 있다.
문제는 n 번째 피보나치 수를 구하기 위해 1과 0을 몇 번이나 반환했는가 그 수를 세는 것이다.
n>=0일때 n번째 피보나치 수를 구하는 재귀 함수는 아래처럼 짤 수 있다.
1 2 3 4 | int fibo(int n){ if(n<=1) return n; else return fibo(n-1) + fibo(n-2); } | cs |
f(3)일 때 0과 1이 몇 번이나 반환하는가를 확인하기 위해 콜트리를 작성해보자.
f(3)의 값을 구하기 위해 f(2)와 f(1)을 호출했고
f(2)의 값을 구하기 위해 f(1)과 f(0)을 호출했다.
f(0)를 한 번 호출해 0을 1회 리턴하고 f(1)을 두 번 호출해 1을 1회 리턴했다.
동적 계획법으로 피보나치 수를 구하는 함수를 다시 사용할 수 있는데 f(1)을 중복호출하는 것을 막아 오버헤드를 줄이기 위함이다.
3번째 피보나치 수에 0,1이 몇 번 쓰였는가 알기 위해 재귀 호출시 카운팅하지 않고 동적 계획법을 사용할 것이다.
f(0)일때 0을 1회 ,1을 0회 반환했고 f(1)일때 0을 0회 ,1을 1회 반환했다.
f(2)일 때 f(1),f(0)를 호출하므로 f(1)과 f(0)가 0,1을 반환한 횟수를 더하기만 하면 된다.
이를 저장하기 위한 자료 구조로 구조체 배열을 생각해볼 수 있다.
f(2)가 0,1을 반환한 횟수를 구하기 위해 다음처럼 구조체 배열의 초기값을 사용하면 된다.
cntFibo[2].zero = cntFibo[0].zero + cntFibo[1].zero
cntFibo[2].one = cntFibo[0].one + cntFibo[1].one
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #include<stdio.h> typedef struct _CountFibo { int zero; int one; }CountFibo; int fibo(int n) { if (n <= 1) return n; else return fibo(n - 1) + fibo(n - 2); } int main() { int T; int N; CountFibo cntFibo[41]; cntFibo[0].zero = 1; cntFibo[0].one = 0; cntFibo[1].zero = 0; cntFibo[1].one = 1; for (int i = 2; i <= 40;i++) { cntFibo[i].zero = cntFibo[i-1].zero + cntFibo[i-2].zero; cntFibo[i].one = cntFibo[i-1].one + cntFibo[i-2].one; } scanf("%d",&T); for (int i = 0; i < T;i++) { scanf("%d",&N); printf("%d %d\n",cntFibo[N].zero, cntFibo[N].one); } return 0; } | cs |
'백준' 카테고리의 다른 글
3054)피터팬 프레임 (0) | 2019.02.06 |
---|---|
11047)동전 0 (0) | 2019.02.04 |
3023)마술사 이민혁 (0) | 2019.02.04 |
2033)반올림 (0) | 2019.02.04 |
1912)연속합 (0) | 2019.02.04 |