재귀 호출만 생각하면 신이 난다! 아닌가요?
다음과 같은 재귀함수 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)를 출력하는 프로그램을 작성하시오. 제한 : -50 ≤ a, b, c ≤ 50
입력은 세 정수 a, b, c로 이루어져 있으며, 한 줄에 하나씩 주어진다. 입력의 마지막은 -1 -1 -1로 나타내며, 세 정수가 모두 -1인 경우는 입력의 마지막을 제외하면 없다.
입력으로 주어진 각각의 a, b, c에 대해서, w(a, b, c)를 출력한다.
1 1 1
2 2 2
10 4 6
50 50 50
-1 7 18
-1 -1 -1
w(1, 1, 1) = 2
w(2, 2, 2) = 4
w(10, 4, 6) = 523
w(50, 50, 50) = 1048576
w(-1, 7, 18) = 1
const fs = require('fs');
let [...input] = fs.readFileSync(0, 'utf-8').toString().trim().split('\n');
let N = input.length - 1;
let abc = [];
for (let i = 0; i < N; i++) {
let [a, b, c] = input[i].trim().split(' ').map(Number);
abc.push([a, b, c]);
}
let dp = new Map();
function recursion(a, b, c) {
let key = `${a} ${b} ${c}`;
if (dp.has(key)) return dp.get(key);
let result;
if (a <= 0 || b <= 0 || c <= 0) {
result = 1;
} else if (a > 20 || b > 20 || c > 20) {
result = recursion(20, 20, 20);
} else if (a < b && b < c) {
result = recursion(a, b, c - 1) + recursion(a, b - 1, c - 1) - recursion(a, b - 1, c);
} else {
result =
recursion(a - 1, b, c) + recursion(a - 1, b - 1, c) + recursion(a - 1, b, c - 1) - recursion(a - 1, b - 1, c - 1);
}
dp.set(key, result);
return result;
}
let answer = '';
for (let i = 0; i < N; i++) {
let key = `${abc[i][0]} ${abc[i][1]} ${abc[i][2]}`;
answer += `w(${abc[i][0]}, ${abc[i][1]}, ${abc[i][2]}) = `;
if (dp.has(key)) answer += dp.get(key) + '\n';
else answer += recursion(abc[i][0], abc[i][1], abc[i][2]) + '\n';
}
console.log(answer.trim());
한동안 프로젝트한다고 문제 풀이를 많이 못해서 못 풀면 어쩌나 싶었는데 그래도 빠르게 풀어서 다행이다... 프로젝트도 좋지만 알고리즘도 꾸준히 푸는 걸 중요시 해야할 것 같다