궤도

[백준] 2225번 : 합분해 본문

💻 현생/⛓ 알고리즘

[백준] 2225번 : 합분해

영이오 2021. 4. 21. 16:52

문제

 


풀이

 

이 문제를 풀기 위해선 2차원 dp배열을 사용해야 한다.

dp[i][j]를 0부터 j까지의 정수 i개를 더해서 그 합이 j가 되는 경우의 수라고 하자.

 

쉽게하기 위해 N=4, K=3이라고 하자.

  0 1 2 3 4
1 1 1 1 1 1
2 1        
3 1        

먼저 K=1인 경우 dp[1][j]=1일 것이다.

0부터 j까지의 정수 1개를 더해서 그 합이 j가 되는 경우의 수는 j 스스로를 사용하는 경우 1개 뿐이기 때문이다.

 

다음으로 N=0인 경우 dp[i][0]=1일 것이다.

몇개의 숫자를 사용한들 그 합이 0이 되기 위해선 0만을 i개 더하는 경우 1개 뿐이기 때문이다.

 

그렇다면 K=2, N=1인 경우를 보자.

0부터 1까지의 정수 2개를 더해서 그 합이 1이 되어야 한다.

 

그 합을 a+b+c+d+e...이런식으로 나타낸다고 치면 a에 올 수 있는 수는 0~1까지 이다.

a=0이라면 그 뒤 정수 1개를 더해 1을 만들어야 하므로 dp[1][1]을 참조하게 된다.

a=1이라면 그 뒤 정수 1개를 더해 0을 만들어야 하므로 dp[1][0]을 참조하게 된다.

 

즉, dp[2][1]=dp[1][0]+dp[1][1]이 되는 것이다.

  0 1 2 3 4
1 1 1 1 1 1
2 1 2 3    
3 1        

마찬가지로 dp[2][2]=dp[1][0]+dp[1][1]+dp[1][2]이다.

이걸 정리하면

 

dp[i][j] = dp[i-1][0]+...+dp[i-1][j]가 된다.

근데 위 표를 잘 보면 한가지 눈치챌 수 있는 것이 있다.

 

파란색으로 표시한 dp[1][0]과 dp[1][1]의 합은 빨간색으로 표시한 dp[2][1]과 같다.

그니까 다시 말해 dp[i][j]에 대해 dp[i-1][0]+...+dp[i-1][j-1] = dp[i][j-1]이다.

 

그러므로 아까 식을 다시 정리하면

dp[i][j] = dp[i][j-1]+dp[i-1][j]가 된다는 것이다.

 

  0 1 2 3 4
1 1 1 1 1 1
2 1 2 3 4 5
3 1 3 6 10 15

표를 다 채우면 이렇게 되고 마지막에 dp[K][N]인 15를 리턴하면 된다.


소스코드

 

#include <iostream>

using namespace std;

const int DIVISOR = 1000000000;
long long dp[201][201];

int dpSeparate(int N, int K) {
    for (int i = 0; i <= N; i++) //K=1일 때
        dp[1][i] = 1;
    for (int i = 2; i <= K; i++) {
        dp[i][0] = 1; //i개의 숫자로 0을 나타내는 방법은 0을 i개 사용하는 방법 1개뿐
        for (int j = 1; j <= N; j++) //dp[i][j-1]에 dp[i-1][0]+...+dp[i-1][j-1]이 있음
            dp[i][j] = (dp[i][j - 1] + dp[i - 1][j]) % DIVISOR;
    }
    return dp[K][N];
}

int main() {
    int N, K;

    cin >> N >> K;
    cout << dpSeparate(N, K);
}
Comments