[백준 15989번] 1, 2, 3, 더하기 4
- 알고리즘 / 문제풀이
- 2024. 5. 28. 00:57
문제 링크
https://www.acmicpc.net/problem/15989
문제 요약
정수 N이 주어졌을 때, 1, 2, 3의 합으로 N을 나타내는 경우의 수를 찾는 문제이다. 순서만 다른 것은 같은 경우라는 것을 주의해야 한다.
문제 풀이
이 문제는 전형적인 동적 계획법(dynamic programming, 이하 DP)로 해결할 수 있다. DP는 상향식과 하향식 두 가지 방법으로 구현할 수 있는데 보통은 하향식 방법이 구현이 쉽고 직관적이다. 하지만 슬라이딩 윈도우, 컨벡스 헐 트릭등 다양한 DP 최적화 전략을 이용하기 위해서라면 상향식 방법도 이용할 줄 알아야 하기 때문에 두 가지 방법으로 모두 구현을 해본다.
하향식으로 문제 풀기
상향식으로 문제를 풀 때 가장 먼저 해야 할 일은 재귀적으로 문제를 해결할 수 있는 완전 탐색 코드를 작성하는 것이다. 다음과 같은 함수를 생각해보자.
순서만 다른 경우는 같은 경우의 수로 계산해야 할 때는 고르는 순서를 한쪽 방향으로 강제하면 쉽게 해결할 수 있기 때문에 함수의 두 번째 인자로
정의한 재귀함수를 코드로 옮기면 다음과 같다.
int calc(int x, int last) {
if (x == 0) {
return 1;
}
int ret = 0;
for (int i = last ; i <= 3 ; ++i) {
if (x - i >= 0) {
ret += calc(x - i , i);
}
}
return ret;
}
구현한 재귀함수에 메모이제이션 패턴을 적용하면 상향식 DP로 문제를 풀게 된다. 전체 코드는 아래 더보기를 클릭하면 볼 수 있다.
#include <stdio.h>
#include <string.h>
int t, n, cache[10010][4];
int calc(int x, int last) {
if (x == 0) {
return 1;
}
int& ret = cache[x][last];
if (ret != -1) {
return ret;
}
ret = 0;
for (int i = last ; i <= 3 ; ++i) {
if (x - i >= 0) {
ret += calc(x - i , i);
}
}
return ret;
}
int main() {
scanf("%d", &t);
memset(cache, -1, sizeof(cache));
while (t--) {
scanf("%d", &n);
printf("%d\n", calc(n, 1));
}
}
상향식으로 문제 풀기
상향식으로 문제를 풀 때는 점화식을 먼저 세워야 한다. 그런데 이 문제 같은 경우 하향식으로 문제를 풀 때 만들었던 재귀함수의 정의를 상향식으로 문제를 풀 때에도 그대로 사용할 수 있다.
dp[0][1] = 1;
for (int i = 1 ; i < 10010 ; ++i) {
for (int j = 1 ; j <= 3 ; ++j) {
for (int k = j ; k <= 3 ; ++k) {
if (i - k >= 0) {
dp[i][k] += dp[i - k][j];
}
}
}
}
그런데 이대로 끝내기에는 뭔가 좀 아쉬운 느낌이 든다. 상향식으로 문제를 풀 경우에는 DP 최적화를 할 수 있다고 했는데, 이 문제는 어떻게 DP 최적화를 할 수 있을까? 하향식으로 문제를 풀 때
상향식으로 접근을 하게 되면, 각 숫자 1, 2, 3을 사용 순서를 반복문 내에서 강제할 수 있기 때문에
dp[0] = 1;
for (int i = 1 ; i <= 3 ; ++i) {
for (int j = i ; j < 10010 ; ++j) {
dp[j] += dp[j - i];
}
}
이렇게 되면
#include <stdio.h>
#include <string.h>
int t, n, dp[10010];
int main() {
scanf("%d", &t);
dp[0] = 1;
for (int i = 1 ; i <= 3 ; ++i) {
for (int j = i ; j < 10010 ; ++j) {
dp[j] += dp[j - i];
}
}
while (t--) {
scanf("%d", &n);
printf("%d\n", dp[n]);
}
}
'알고리즘 > 문제풀이' 카테고리의 다른 글
[백준 17845] 수강 과목 (0) | 2024.06.11 |
---|---|
[백준 2417번] 정수 제곱근 (0) | 2024.05.30 |
[백준 17086번] 아기 상어 2 (0) | 2024.05.26 |
[백준 9376번] 탈옥 (0) | 2024.05.23 |
[백준 10021번] Watering the Fields (0) | 2024.05.20 |