본문 바로가기

뭐라도 공부해보자!!( 이론 )/자료구조 및 알고리즘

백준 15990, 1, 2, 3 더하기 5

반응형

문제

정수 4를 1, 2, 3의 합으로 나타내는 방법은 총 3가지가 있다. 합을 나타낼 때는 수를 1개 이상 사용해야 한다. 단, 같은 수를 두 번 이상 연속해서 사용하면 안 된다.

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

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

입력

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

출력

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

예제 입력 1 

3
4
7
10

예제 출력 1 

3
9
27

 

 다이나믹 프로그래밍 방식으로 경우의 수를 구하는 것은 많이 하였다. 이 번 문제는 여기에 연속하여 같은 수를 더해서는 안된다는 제한 조건이 붙었다. 다소 복잡해 보이지만, 제한 조건을 만족하는 지 확인하기 위해서는 그에 맞추어 나누어 저장할 필요가 있음을 생각해낼 수 있다면 충분히 풀 수 있다. 

 기본적인 골자는 n 을 만들어내는 합의 경우의 수를 n-1, n-2, n-3 의 경우의 수로 부터 이끌어내는 것은 같다. 다만 n 의 경우의 수를 마지막으로 1 을 더한 경우, 2 를 더한 경우, 3 을 더한 경우로 나누어 이중배열 형태로 저장할 것이다. 우리는 다음과 같은 결과를 이끌어 낼 수 있을 것이다.

자연수 i 의 합 조합에 대하여

cases[i][1] = cases[i-1][2] + cases[i-1][3]; //case[i-1][1]은 제외(중복 조건 위배)
cases[i][2] = cases[i-2][1] + cases[i-2][3]; //case[i-2][2]은 제외(중복 조건 위배)
cases[i][3] = cases[i-3][1] + cases[i-3][2]; //case[i-3][3]은 제외(중복 조건 위배)

 

 나는 다음과 같이 문제를 풀었다.

 

  1. 테스트 개수와 입력 값들을 받는다.
  2. 입력값 중 가장 큰 값(max_num)을 구한다.
  3. 이중 배열 cases[n][4] 를 선언한다.
  4. cases[1][1], cases[2][2], cases[3][1], cases[3][2], cases[3][3]의 값을 미리 채워 놓는다. 
  5. 4 인 경우부터 max_num인 경우 까지 이중 배열 cases를 채워 놓는다. 수가 커지는 관계로 미리 모듈러 연산을 하였다.
  6. 각각의 입력에 대해 1 을 마지막으로 더한 경우, 2 를 마지막으로 더한 경우, 3 을 마지막으로 더한 경우를 모두 더한 후 모듈러 연산을 해준 후 출력한다.  

 

 코드는 다음과 같다.

 

#include <iostream>
#include <algorithm>
#include <vector>

int cases[100001][4];

int main() 
{
	int N;
	std::cin >> N;

	std::vector<int> input;

	cases[1][1] = 1;
	cases[2][2] = 1;
	cases[3][1] = 1;
	cases[3][2] = 1;
	cases[3][3] = 1;

	for (int i = 0; i < N; i++) 
	{
		int data;
		std::cin >> data;
		input.push_back(data);
	}

	int max_input = *std::max_element(input.begin(), input.end());

	for (int i = 4; i <= max_input; i++)
	{
		cases[i][1] = (cases[i-1][2] + cases[i-1][3]) % 1000000009;
		cases[i][2] = (cases[i-2][1] + cases[i-2][3]) % 1000000009;
		cases[i][3] = (cases[i-3][1] + cases[i-3][2]) % 1000000009;
	}

	for (int i = 0; i < input.size(); i++) 
	{
		std::cout << 
			((long long)cases[input[i]][1] + cases[input[i]][2] + cases[input[i]][3]) % 1000000009
			<< '\n';
	}

	return 0;
}

 

 제한 조건을 어떻게 풀 것인가에 대해서 생각해 볼만한 문제였다. 이 것으로 글을 마친다.

반응형