백준 문제풀이/etc

[재귀] BOJ 9095 : 1, 2, 3 더하기

준코딩 2019. 10. 14. 00:50

문제


정수 4를 1, 2, 3의 합으로 나타내는 방법은 총 7가지가 있다. 합을 나타낼 때는 수를 1개 이상 사용해야 한다.

  • 1+1+1+1
  • 1+1+2
  • 1+2+1
  • 2+1+1
  • 2+2
  • 1+3
  • 3+1

정수 n이 주어졌을 때, n을 1, 2, 3의 합으로 나타내는 방법의 수를 구하는 프로그램을 작성하시오.

 

입력


첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고, 정수 n이 주어진다. n은 양수이며 11보다 작다.

 

 

출력


각 테스트 케이스마다, n을 1, 2, 3의 합으로 나타내는 방법의 수를 출력한다.

풀이


 

요즘 재귀 함수를 구현하는 법을 많이 연습 중입니다.

브루트 포스 문제들을 해결할 때 재귀 함수가 많은 도움이 되기 때문입니다.

 

 

이 문제는 재귀를 처음 접할 때 좋을 것이라 생각돼서 가져와보았습니다.

 

 

재귀 함수를 만들기 전에 설계를 잘해야 구현이 쉬워요.

1, 2, 3의 합으로 5를 만드는 방법의 수는

5에 1, 2, 3을 빼서 0을 만드는 방법의 수와 같습니다.

 

 

https://ssu-gongdoli.tistory.com/36

위 그림에서 5를 0으로 만드는 모든 경우의 수를 보여주지는 않았지만

한 가지 파악할 수 있는 부분이 있습니다.

 

5를 0으로 만드는 방법의 수는 4, 3, 2를 0으로 만드는 

방법의 수를 더한 것과 같다.

 

그리고 이 4, 3, 2는 5에서 1, 2, 3을 뺀 수와 같습니다.

 

바로 이 부분, 계산을 해서 나온 값들이 이전 값의 결과에 영향을 미치는 부분을 찾으면

재귀 함수의 설계는 거의 끝납니다.

 

여기까지 설계가 되면 도출될 수 있는 함수의 모양은 이렇습니다.

 

 

하지만, 이렇게만 하면 재귀 함수는 무한적으로 실행됩니다.

때문에 재귀가 끝나는 조건을 설정해줍니다.

 

1. N 이 0보다 작아진 경우 0을 리턴

2. N 이 1 보다 작거나 같은 경우 1을 리턴

 

여기까지 설계하면 재귀 함수가 완성됩니다.

코드


#include <iostream>

using namespace std;

int go(int n) {
	
	if (n < 0) return 0;
	if (n <= 1) return 1;
	return go(n - 1) + go(n - 2) + go(n - 3);
}


int main() {
	int k;
	cin >> k;

	while (k--) {
		int n;
		cin >> n;
		cout << go(n) << '\n';
	}
	return 0;
}