일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 항해99
- 정렬
- 데이터베이스
- 알고리즘
- 완전탐색
- Til
- 자바
- 개발자취업
- 99클럽
- 스프링
- BinarySearch
- 트리
- 백준
- 동적 프로그래밍
- DP
- 코딩테스트준비
- 스프링 핵심 원리 - 기본편
- 프로그래머스
- 그래프
- 네트워크 계층
- 그리디
- lower bound
- Java
- DFS
- BFS
- Spring
- 그래프 이론
- 브루트포스
- 우선순위큐
- 백트래킹
- Today
- Total
AtraFelis's Develop Diary
[99클럽 코테스터디 24일차 TIL / 백준] 2225 - 합분해 (DP) 본문
99클럽 코테스터디 24일차 TIL
KeyWord : DP
문제
0부터 N까지의 정수 K개를 더해서 그 합이 N이 되는 경우의 수를 구하는 프로그램을 작성하시오.
덧셈의 순서가 바뀐 경우는 다른 경우로 센다(1+2와 2+1은 서로 다른 경우). 또한 한 개의 수를 여러 번 쓸 수도 있다.
입력
첫째 줄에 두 정수 N(1 ≤ N ≤ 200), K(1 ≤ K ≤ 200)가 주어진다.
출력
첫째 줄에 답을 1,000,000,000으로 나눈 나머지를 출력한다.
풀이
N과 K의 크기를 1부터 증가시키며 메모제이션 하여 해결할 수 있다.
dp[k+1][n+1]
라는 배열을 선언한 후, dp[i][j]
에 각 경우의 수를 저장해가는 식으로 진행하자.
문제에서 주어진 예제입력 6 4
를 기준으로 dp 배열을 시각적으로 나타내보았다.
K\N | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
2 | 1 | ||||||
3 | 1 | ||||||
4 | 1 |
일단 초기 dp가 이렇게 만들어진다는 것까지는 쉽게 이해된다. N=0일 때는 K가 얼마가 되든 K개의 0을 더하는 경우의 수 1, K=1일 때는 자기자신 하나만 포함하는 경우의 수 1이 된다.
이제 나머지 빈칸을 어떻게 채울지 고민해야 한다.
수가 너무 작으면 이해하기 힘드므로 dp[3][2]
일 때를 생각해보자.
- 0 + 0 + 2
- 0 + 2 + 0
- 2 + 0 + 0
- 0 + 1 + 1
- 1 + 0 + 1
- 1 + 1 + 0
일단 dp[3][2]
는 이렇게 6개의 경우의 수가 나온다. 하지만 우리는 여기서 규칙성을 찾아야 한다.
- 2개의 수를 사용하여 0을 만드는 경우의 수는 1이다.
dp[2][0] = 1
- 여기에 2만 더하면 0 + 2가 되므로 2가 만들어진다.
- 2개의 수를 사용하여 1을 만드는 경우의 수는 2이다.
dp[2][1] = 2
→0 + 1
/0 + 1
- 여기에 1을 더하면
1 + 1
이 되므로 2가 만들어 진다.
- 2개의 수를 사용하여 2를 만드는 경우의 수는 2이다.
dp[2][2] = 3
→0 + 2
/1 + 1
/2 + 0
- 여기에 0을 더하면
2 + 0
이 되므로 2가 만들어진다.
이렇게 만들어지는 모든 경우의 수를 더하면 6이 도출된다.
즉, dp[3][2]
= dp[2][0]
+ dp[2][1]
+ dp[2][2]
이런 수식이 도출된다.
이 규칙성에 따라 식을 일반화 하면, dp[i][j]
= dp[i-1][0]
+ dp[i-1][1]
+ ... + dp[i-1][j]
이 된다.
이제 이 식을 이용하여 dp 배열을 채워보자.
K\N | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
2 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
3 | 1 | 3 | 6 | 10 | 15 | 21 | 28 |
4 | 1 | 4 | 10 | 20 | 35 | 56 | 84 |
해를 구했다. 당연히 dp[4][6]
에 저장된 84가 문제의 해다.
이렇게만 해도 코드를 구현할 수는 있겠지만, 뭔가 계산량을 더 줄일 수 있을 것 같다. 이 상태로 구현을 한다면 3중 반복문을 사용해야 한다. 2중 반복만 되어도 불편한데, 3중이라니?
조금 더 규칙성을 찾아보자.
dp[3][2]
= dp[2][0]
+ dp[2][1]
+ dp[2][2]
이 수식을 자세히 살펴보면, dp[2][0] + dp[2][1] = dp[3][1]
이라는 사실을 알 수 있다.
식을 더 정리하면, dp[3][2] = dp[3][1] + dp[2][2]
이다. 이를 일반화 하면, dp[i][j] = dp[i-1][j] + dp[i][j-1]
이 된다.
이제 진짜 코드로 구현하자.
코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stk = new StringTokenizer(br.readLine());
int n = Integer.parseInt(stk.nextToken());
int k = Integer.parseInt(stk.nextToken());
int[][] dp = new int[k + 1][n+1];
Arrays.fill(dp[1], 1);
for (int i = 0; i < k + 1; i++) {
dp[i][0] = 1;
}
for (int i = 1; i <= k; i++) {
for (int j = 1; j <= n; j++) {
dp[i][j] = (dp[i][j - 1] + dp[i - 1][j]) % 1000000000;
}
}
System.out.println(dp[k][n]);
}
}
'Algorithm > 백준' 카테고리의 다른 글
[백준 | JAVA] 27527 - 배너 걸기 (슬라이딩 윈도우) (0) | 2025.02.24 |
---|---|
[99클럽 코테스터디 25일차 TIL / 백준] 1351 - 무한 수열 (DP, HashMap) (0) | 2025.02.21 |
[99클럽 코테스터디 23일차 TIL / 백준] 9251 - LCS (DP) (0) | 2025.02.19 |
[99클럽 코테스터디 22일차 TIL / 백준] 11053 - 가장 긴 증가하는 부분 수열(DP) (0) | 2025.02.18 |
[99클럽 코테스터디 21일차 TIL / 백준] 1003 - 피보나치 함수 (DP) (0) | 2025.02.17 |