algorithm/BOJ

BOJ 15989번 1, 2, 3 더하기 4

_JunHo 2020. 2. 18. 20:34

BOJ : https://www.acmicpc.net/problem/15989

github : https://github.com/junho0956/Algorithm/blob/master/15989/15989/%EC%86%8C%EC%8A%A4.cpp

 

문제를 풀고나서 다른분들의 코드를 참고해봤는데

다들 1차원 dp로 푸시던데 저는 1,2,3 크기인 3*n 형태의 2차원 dp로 해결하였습니다.

 

dp[i][num] 의 의미는

현재 숫자 i를 기준 num 을 만들수있는 경우의 수를 의미합니다.

dp 를 설명하기 위해 풀이를 천천히 해보겠습니다.

 

1,2,3 으로 임의의 수 num 을 만들기 위해서는 1,2,3 더하기 의 기본문제처럼 풀게되면

112 121 211 같은 합의 경우는 같은데 경우의 수는 다르게 두는 '중복' 이 발생하게 됩니다.

이런 중복을 모두 같은 경우의 수로 보려면 1, 2, 3 을 이용해서

내림차순으로 만들거나 오름차순으로 만드는 둘중 한가지의 방법을 선택해야 된다고 생각했습니다.

만약 오름차순으로 한다고 가정하고, 1과 2만 사용한다고 생각한다면

1 1 2 라는 경우가 생기지만 1 2 1 , 2 1 1 같은 경우는 생기지 않기 때문입니다.

마찬가지로 1 3 은 되지만, 3 1 은 만들어지지 않는다는 뜻입니다.

 

저는 이를 위에서 말씀드린 점화식 dp[i][num] : 현재 숫자 i로 num을 만들 수 있는 경우의 수로 표현하였고

코드를 보시면 아시겠지만 내림차순으로 해결하였습니다.

현재 숫자가 2 이면 2와 1만 사용하지 3은 사용하지 않게 되는 것입니다.

 

아래에서 num은 만들어야하는 수이고, stand 는 3,2,1 중 1가지 숫자가 됩니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <algorithm>
using namespace std;
 
int n;
int dp[4][10001];
 
int dfs(int num, int stand) {
    // 중복없는 dfs를 만들어야 된다
    // 112 == 121 == 211 과 같은
    // 이럴 경우 오름차순 또는 내림차순에 의해서만 만들어지는 경우의 수를 구한다면 중복이 사라질 것이다
 
    if (num < 0return 0;
    if (num == 0return 1;
 
    int& res = dp[stand][num];
    if (res) return res;
 
    for (int i = stand; i >= 1; i--)
        res += dfs(num - i, i);
 
    return res;
}
 
int main() {
    ios::sync_with_stdio(0), cin.tie(0);
 
    int T; cin >> T;
 
    while (T--) {
        cin >> n;
        cout << dfs(n, 3)<< "\n";
    }
 
    return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter