공부/백준

9461번: 파도반 수열(백준 C++)

상연 2020. 11. 16. 22:15

목차

    9461번: 파도반 수열 링크

    코드

    #include <iostream>
    #include <vector>
    using namespace std;
    
    vector<long long> v(4, 1);
    //P(1) ~ P(3) 1, 1, 1 P(0)은 존재하지 않지만 편의상 생성.
    
    void solve(int n){
        int l = v.size() - 1;
        //주어진 n의 크기가 Vector v의 크기보다 작으면 바로 출력.
        if(n > l){
        //주어진 n의 크기가 Vector v의 크기보다 크면
        //현재까지 구한 P의 값 이후부터 시작해서 P(n) 산출
        //점화식 P(n) = P(n-3) + P(n-2)
            for(int i = l+1; i<=n; i++){
                v.push_back(v[i-3] + v[i-2]);
            }
        }
        printf("%lld\n", v[n]);
    }
    
    int main() {
        int t, n;
        scanf("%d", &t);
        for(int i=0; i<t; i++){
            scanf("%d", &n);
            solve(n);
        }
    }

    풀이 및 사견

    문제

    위 사진과 같은 모양으로 삼각형을 배치할 때 n번째 배치하는 삼각형의 변의 크기는 무엇인가? 가 문제다.
    사실 나의 경우에는 그림은 안 보고 문제에 주어진 N이 1~10까지의 수 배열을 보고 풀었다.

    P(1)부터 P(10)까지 첫 10개 숫자는 1, 1, 1, 2, 2, 3, 4, 5, 7, 9이다.

    여기서 점화식을 추측해 낼 수 있기 때문.

    점화식 1

    그림을 안 보고 P(1) ~ P(10)까지의 수열만 보았을때 추측한 점화식은 아래와 같다.

    P(N) = P(N-3) + P(N-2) , (N >= 4)

    점화식 2

    그림을 보고 알 수 있는 점화식은 아래와 같다.

    P(N) = P(N-1) + P(N-5), (N >= 6)

    풀이

    기존에 작성한 코드의 경우는 점화식 1을 가지고 작성된 코드이다.
    아무생각없이 그림을 안 봐도 점화식이 보이는 것 같아 이렇게 풀었는데 글을 작성하며 그림을 보는데 점화식 2가 생각이 났다.

    그래서 곧바로 점화식 2로 코드를 작성해 보았다.

    #include <iostream>
    #include <vector>
    using namespace std;
    
    vector<long long> v(4, 1);
    //P(1) ~ P(3) 1, 1, 1 P(0)은 존재하지 않지만 편의상 생성.
    
    void solve(int n){
        int l = v.size() - 1;
        //주어진 n의 크기가 Vector v의 크기보다 작으면 바로 출력.
        if(n > l){
        //주어진 n의 크기가 Vector v의 크기보다 크면
        //현재까지 구한 P의 값 이후부터 시작해서 P(n) 산출
        //점화식 P(n) = P(n-5 + P(n-1)
            for(int i = l+1; i<=n; i++){
                v.push_back(v[i-1] + v[i-5]);
            }
        }
        printf("%lld\n", v[n]);
    }
    
    int main() {
        v.push_back(2); //P(4)
        v.push_back(2); //P(5)
        int t, n;
        scanf("%d", &t);
        for(int i=0; i<t; i++){
            scanf("%d", &n);
            solve(n);
        }
    }

    정답이다.

    아마 문제가 원래 원했던 정답은 점화식 2에 더 가깝지 않을까 생각이 들긴 한다.

    점화식은 위의 두 개와 같으며, 또한 문제를 푸는 방법에 있어서도 두 가지를 생각해봤다.

    여러개의 변수 사용하여 풀기

    점화식이 P(N) = P(N-3) + P(N-2) , (N >= 4)라면
    변수를 4개 설정한다. temp1, temp2, temp3, n
    temp1 -> P(N-3)
    temp2 -> P(N-2)
    temp3 -> P(N-1)
    n -> P(N-3) + P(N-2)

    • N = 4
      n = temp1 + temp2
      temp1 = temp2
      temp2 = temp3
      temp3 = n

    즉, n에 P(n) 값을 구해서 추가하고
    temp1~3 을 index 하나씩 미뤄주는 것이다.

    이 방법을 사용한 코드는 이와 같다.

    #include <iostream>
    
    using namespace std;
    
    long long padovan(int n){
        long long n1 = 1;
        long long n2 = 1;
        long long n3 = 1;
        long long ans;
        if (n < 4) { return 1; }
        for (int i = 4; i <= n; i++) {
            ans = n1 + n2;
            n1 = n2;
            n2 = n3;
            n3 = ans;
        }
        return ans;
    }
    
    int main() {
        int t;
        cin >> t;
        for (int i = 0; i < t; i++) {
            int n;
            cin >> n;
            cout << padovan(n) << "\n";
        }
    }

    Vector 사용하여 저장하기.

    내가 푼 방법이다.

    점화식이 P(N) = P(N-3) + P(N-2) , (N >= 4)라면
    변수 vector v를 생성하고 v = {1,1,1}로 초기화한다.
    (나의 경우에는 index 1부터 시작하기 위해서 편의상 v[0]에도 1을 넣어놨다.)

    초기상태의 벡터이다.
    이후 P(4)를 구해야 한다고 하자.

    초기상태의 벡터는 크기가 3이기 때문에 주어진 N인 6보다 작다.
    따라서 점화식을 사용하여 P(6)을 구한다.
    점화식의 시작은 벡터의 크기 + 1인 N = 4부터 시작해서 N = 6까지이며 이때까지의 값은 벡터에 저장한다.

    다음 N = 5일때를 구해보자

    이미 이전에 우리는 N = 6까지 구해놨다.
    이는 벡터의 크기가 현재 6으로 주어진 수 N보다 크다는 것으로 알 수있다.
    따라서 추가적으로 점화식을 할 필요없이 바로 출력한다.

    다음 N = 8일때를 구해보자

    마찬가지로 N = 8로 벡터의 크기인 6보다 크므로
    벡터의 크기 + 1인 7부터 8까지 점화식을 진행해주면 점화식을 알 수 있다.

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

    1932번: 정수 삼각형(백준 C++)  (0) 2020.11.18
    1149번: RGB거리(백준 C++)  (0) 2020.11.17
    1904번: 01타일(백준 C++)  (0) 2020.11.15
    1003번: 피보나치 함수(백준 C++)  (0) 2020.11.14
    2748번: 피보나치 수2(백준 C++)  (0) 2020.11.13