호우동의 개발일지

Today :


문제 이해 단계

 

정수 n이 주어지면, 그냥 1,2,3 합의 조합으로 경우의 수를 구한다.
순서가 바뀌는 것도 다른 경우의 수로 취급한다.

 


문제 접근 단계

N이 1일 때부터 하나씩 살펴보겠다.

N = 1 -> 1개
- 1 

N = 2 ->2개
- 1 + 1
- 2

N = 3 -> 4개
- 1 + 1 + 1
- 1 + 2
- 2 + 1
- 3

N = 4 -> 7개
- 1 + 1 + 1 + 1
- 1 + 1 + 2
- 1 + 2 + 1
- 2 + 1 + 1
- 2 + 2
- 1 + 3
- 3 + 1

N = 5 -> 13개
- 1 + 1 + 1 + 1 + 1
- 1 + 1 + 1 + 2
- 1 + 1 + 2 + 1
- 1 + 2 + 1 + 1
- 2 + 1 + 1 + 1
 - 1 + 2 + 2
- 2 + 1 + 2
- 2 + 2 + 1
- 1 + 1 + 3
- 1 + 3 + 1
- 3 + 1 + 1
- 2 + 3
- 3 + 2

이렇게 나열해 봤을 때, 자세히 보면 N이 4,5일 때 패턴을 볼 수 있다.

문제에서 N이 1,2,3의 합으로 이뤄진다고 했는데,
1,2,3일 때의 경우의 수 양상이
4,5에서도 포함돼서 나타나는 것을 볼 수 있다.

N = 4 일 때 맨 처음이 1로 시작하는 합의 조합만 뽑아보면
- 1 + 1 + 1 + 1
- 1 + 1 + 2
- 1 + 2 + 1
- 1 + 3


인데 여기서 맨 앞에 1을 제외하면
뒤에 있는 수는 정확히 N= 3일 때의 합의 조합과 같다.

N = 3 일 때의 합의 경우의 수를 DP(3)이라고 하면
이는 1 + DP(3)이라고 할 수 있다.

이를 이용해서 다른 수들도 나타낼 수 있다.

4 = 1 + 3 = 2 + 2 = 3 +1 이기 때문에
1 + DP(3) = 2 + DP(2) = 3 + DP(1)이다.

우리가 구해야 하는 것은 경우의 수이다.


시작하는 수가 1,2,3으로 모두 다르므로 모두 다른 경우의 수로 볼 수 있다.
따라서 DP(4) = DP(3) + DP(2) + DP(1)이라고 할 수 있다.

이는 N = 5 일 때도 마찬가지일 것이다.
5 = 4 + 1 = 3 + 2 = 2 + 3이기 때문이다.

즉 이를 점화식으로 표현하면
DP(N) = DP(N-1) + DP(N-2) + DP(N-3)이다.

이제 이를 이용해서 코드를 구현해 보겠다.

 


문제 구현 단계

int d[12];
int dp(int x) {
	if (x == 1) return d[x] = 1;
	if (x == 2) return d[x] = 2;
	if (x == 3) return d[x] = 4;

	if (d[x] != 0) return d[x];

	return d[x] = dp(x - 3) + dp(x - 2) + dp(x - 1);
}

핵심이 되는 dp함수이다. 매개변수로 N을 받는다.
x가 1,2,3 일 때는 각각의 경우의 수를 미리 반환한다.

그리고 이미 dp값이 있는 경우에는
설정해 뒀던 값을 반환하여 시간낭비를 줄인다.

그리고 위에서 설명했듯이 점화식을 사용해 준다.

아래는 전체코드를 올리고 설명을 마치겠다.

#include <iostream>

using namespace std;

int d[12];
int dp(int x) {
	if (x == 1) return d[x] = 1;
	if (x == 2) return d[x] = 2;
	if (x == 3) return d[x] = 4;

	if (d[x] != 0) return d[x];

	return d[x] = dp(x - 3) + dp(x - 2) + dp(x - 1);
}
int main() {
	cin.tie(0);
	cout.tie(0);
	ios::sync_with_stdio(false);

	int T, n;
	cin >> T;

	while (T--) {
		cin >> n;
		cout << dp(n) << "\n";
		for (int i = 0; i < 12; i++) {
			d[i] = 0;
		}
	}
}

테스트 케이스 T가 여러 번이기 때문에 한번 실행할 때마다
배열 d를 초기화해 주는 작업을 추가하였다.

 


시행착오

이 문제는 풀 때는 그리 어렵지 않게 풀고
풀이를 블로그에 올리지 않고 있다가 발표 준비로 작성하였다.

근데 내가 쓴 코드를 다시 보니 왜 이렇게 쓴지도 모르겠고
이 문제를 다시 풀어보니 못 풀겠어서 몹시 당황했다.

역시 컨디션 따라 문제를 못 풀 수도 있겠구나도 싶었고, 꺼진 불도 다시 보자 싶었다.