백준 신나는 함수 실행 [c++]

신나는 함수 실행 실버2

문제

재귀 호출만 생각하면 신이 난다! 아닌가요?

다음과 같은 재귀함수 w(a, b, c)가 있다.

if a <= 0 or b <= 0 or c <= 0, then w(a, b, c) returns: 1

if a > 20 or b > 20 or c > 20, then w(a, b, c) returns: w(20, 20, 20)

if a < b and b < c, then w(a, b, c) returns: w(a, b, c-1) + w(a, b-1, c-1) - w(a, b-1, c)

otherwise it returns: w(a-1, b, c) + w(a-1, b-1, c) + w(a-1, b, c-1) - w(a-1, b-1, c-1) 위의 함수를 구현하는 것은 매우 쉽다. 하지만, 그대로 구현하면 값을 구하는데 매우 오랜 시간이 걸린다. (예를 들면, a=15, b=15, c=15)

a, b, c가 주어졌을 때, w(a, b, c)를 출력하는 프로그램을 작성하시오.

풀이

  • 주어진 제귀함수를 개선하는 문제.
  • w(5,5,5)도 실행시간이 오래걸려 결과가 나오지 않았다.
  • 일단 중간에 반복되어 쓰이는 값이 존재해 메모이제이션 적용해봄.
  • 해결.

코드

#include <iostream>
#include <string>
#include <vector>
using namespace std;

int stored[21][21][21];

int w(int a, int b, int c){
    // cout << "w(" << a << " " << b << " " << c << ")" << endl;
    if(a <= 0 || b <= 0 || c <= 0){
        return 1;
    } 
    if(a > 20 || b > 20 || c > 20){
        return w(20,20,20);
    } 

    if(stored[a][b][c]){
        return stored[a][b][c];
    }
    
    if( a < b && b < c){ 
        stored[a][b][c] = w(a, b, c-1) + w(a, b-1, c-1) - w(a, b-1, c);
        return stored[a][b][c];
    } else{
        stored[a][b][c] = w(a-1, b, c) + w(a-1, b-1, c) + w(a-1, b, c-1) - w(a-1, b-1, c-1);
        return stored[a][b][c];
    }
}

int main(){
    // cout << w(5, 5, 1) << endl;
    string str;
    string end_point = "-1 -1 -1 ";
    getline(cin, str);
    str += " ";
    while(end_point.compare(str) != 0){
        string delim = " ";
        vector<string> words;

        size_t pos = 0;
        while((pos = str.find(delim)) != string::npos)
        {
            words.push_back(str.substr(0, pos));
            str.erase(0, pos + delim.length());
        }

        int num[3];
        for(int i = 0; i < 3; i++)
        {
            num[2-i] = stoi(words.back());
            words.pop_back();
        }
        // cout << num[0] << num[1] << num[2] << endl;
        cout << "w(" << num[0] << ", " << num[1] << ", " << num[2] << ") = ";
        cout << w(num[0], num[1], num[2]) << endl;
        getline(cin, str);
        str += " ";
    }


    return 0;
}

총평

  • 메모이제이션 한방으로 해결되어 실버인듯.
  • 그런데 입력을 string으로 받아 파싱한 후 int로 변환했는데 생각해보니 그냥 int로 받아 사용해도 됬을 것 같다.