반응형
11-30 14:17
Today
Total
«   2024/11   »
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
관리 메뉴

개발하는 고라니

[백준] 1003번 : 피보나치 함수 본문

Programming/백준

[백준] 1003번 : 피보나치 함수

조용한고라니 2021. 1. 11. 02:16
반응형
 

1003번: 피보나치 함수

각 테스트 케이스마다 0이 출력되는 횟수와 1이 출력되는 횟수를 공백으로 구분해서 출력한다.

www.acmicpc.net

# 입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다.
각 테스트 케이스는 한 줄로 이루어져 있고, N이 주어진다. N은 40보다 작거나 같은 자연수 또는 0이다.

# 출력

각 테스트 케이스마다 0이 출력되는 횟수와 1이 출력되는 횟수를 공백으로 구분해서 출력한다.

# 예제 입력

3
0
1
3

# 예제 출력

1 0
0 1
1 2

문제를 보면 우리가 흔히 알고있는 피보나치 수열 문제처럼 재귀적인 방법으로 풀 수 있다. 하지만 정답의 조건 때문에 이 문제는 동적 프로그래밍(Dynamic Programming)으로 해결해야 한다. 바로 "시간" 때문이다.

0<= N <= 40 이므로 40이 3회 주어졌다고 가정해보면, 0.25s 만에 프로그래밍을 마치는 것은 어렵다고 생각된다. 따라서 반복적인 호출이 많은 부분이므로 동적 프로그래밍을 이용하여 문제를 풀어보자.

 

피보나치 수열 함수를 f()라고 하자. n >= 2일 때 f(n-1) + f(n-2) 이다. 지금은 f(n)의 값을 찾는 것이 아닌 f(n)에서 f(0)과 f(1)을 몇 번 호출하느냐가 문제이므로,

 

f(0) = [1, 0]

f(1) = [0, 1]

f(2) = f(0) + f(1) = [1, 1]

f(3) = f(2) + f(1) = (f(0) + f(1)) + f(1) = [1, 2]

...

 

따라서 f(n)의 f(0), f(1) 호출 횟수는 f(n) = f(n-1)의 f(0), f(1) 호출 횟수 + f(n-2)의 f(0), f(1) 호출 횟수와 같다.

먼저, 2차원 배열 long arr[41][2]가 필요하다. (arr[i][0] : 0의 개수, arr[i][1] : 1의 개수)

static void fibo(int n){

  arr[0][0] = 1; arr[0][1] = 0;
  arr[1][0] = 0; arr[1][1] = 1;

  for (int i = 2; i <= n; i++) {
    arr[i][0] = arr[i - 1][0] + arr[i - 2][0];
    arr[i][1] = arr[i - 1][1] + arr[i - 2][1];
  }
}

만약 이 함수가 1번만 실행이 된다면 상관없지만, 5번 실행된다면?

n = [10, 7, 5, 3, 13] 순으로,

10이 들어오고 arr[10][0] arr[10][1] 까지는 값이 채워져 있다.

7이 들어왔을 때 arr[7][0] arr[7][1] 은 이미 값이 채워져 있는대도 for루프가 실행이 된다.

 

전역 변수로 max를 만들어서 인자로 들어오는 n과 max를 비교해서 n < max라면 for루프를 실행시키지 않도록 하자.

 

    static int max = 2;
    static long[][] arr = new long[41][2];

    static void fibo(int n){
        arr[0][0] = 1; arr[0][1] = 0;
        arr[1][0] = 0; arr[1][1] = 1;

        if(n > max) {
            for (int i = max; i <= n; i++) {
                arr[i][0] = arr[i - 1][0] + arr[i - 2][0];
                arr[i][1] = arr[i - 1][1] + arr[i - 2][1];
            }
            max = n;
        }
        System.out.printf("%d %d\n", arr[n][0], arr[n][1]);
    }

 

이제 main()에서는 T와 N값들을 입력받아 함수 인자로 넘겨주기만 하면 끝이다.


# Java Code </>

public class Main {

    static int max = 2;
    static long[][] arr = new long[41][2];

    static void fibo(int n){
        arr[0][0] = 1; arr[0][1] = 0;
        arr[1][0] = 0; arr[1][1] = 1;

        if(n > max) {
            for (int i = max; i <= n; i++) {
                arr[i][0] = arr[i - 1][0] + arr[i - 2][0];
                arr[i][1] = arr[i - 1][1] + arr[i - 2][1];
            }
            max = n;
        }
        System.out.printf("%d %d\n", arr[n][0], arr[n][1]);
    }
    
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);

        int T = sc.nextInt();

        long start = System.currentTimeMillis();
        for(int i=0; i<T; i++)
            fibo(sc.nextInt());

        long end = System.currentTimeMillis();
        System.out.println( "실행 시간 : " + ( end - start )/1000.0 +"초");
    }
}

그런데 시간제한이 0.25초라... Java의 Scanner를 사용하면 시간 초과가 발생한다 ㅠㅠ.. 참고로 백준에서 제출 시 Java를 이용한다면.. java - java(openJDK) - java 11 순으로 빠르다고 한다. 계속 시간 초과가 나니까 짜증나서 그냥 C로 제출해버렸다.

 

# C Code </>

#include <stdio.h>

int max = 2;
long arr[41][2];

void fibo(int n) {

	arr[0][0] = 1; arr[0][1] = 0;
	arr[1][0] = 0; arr[1][1] = 1;

	if (n >= max) {
		for (int i = max; i <= n; i++) {
			arr[i][0] = arr[i - 1][0] + arr[i - 2][0];
			arr[i][1] = arr[i - 1][1] + arr[i - 2][1];
		}
		max = n;
	}
	printf("%d %d\n", arr[n][0], arr[n][1]);
}

int main(void) {

	int T, n;
	scanf("%d", &T);

	for (int i = 0; i < T; i++) {
		scanf("%d", &n);
		fibo(n);
	}
}
반응형

'Programming > 백준' 카테고리의 다른 글

[백준] 10844번 : 쉬운 계단 수  (0) 2021.01.15
[백준] 1463번 : 1로 만들기  (0) 2021.01.15
[백준] 2579번 : 계단 오르기  (0) 2021.01.14
[백준] 1149번 : RGB거리  (0) 2021.01.13
[백준] 9184번 : 신나는 함수 실행  (0) 2021.01.11
Comments