728x90
1 초 (추가 시간 없음) | 512 MB | 114351 | 75419 | 52026 | 64.454% |
문제
정수 4를 1, 2, 3의 합으로 나타내는 방법은 총 7가지가 있다. 합을 나타낼 때는 수를 1개 이상 사용해야 한다.
- 1+1+1+1
- 1+1+2
- 1+2+1
- 2+1+1
- 2+2
- 1+3
- 3+1
정수 n이 주어졌을 때, n을 1, 2, 3의 합으로 나타내는 방법의 수를 구하는 프로그램을 작성하시오.
입력
첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고, 정수 n이 주어진다. n은 양수이며 11보다 작다.
출력
각 테스트 케이스마다, n을 1, 2, 3의 합으로 나타내는 방법의 수를 출력한다.
예제 입력 1
3
4
7
10
예제 출력 1
7
44
274
풀이✔
1️⃣ 문제 분석하기
- 정수 n이 주어질 때, n을 1,2,3의 합으로 나타내는 방법의 수를 구해야함
- 숫자는 1,2,3 만 사용을 해야함.
2️⃣ 요구 조건 구현하기
- 테스트 케이스의 개수 T가 주어짐
- 정수 n이 주어지며, n은 양수고, 11보다 작다.
- n에 따른 총 경우의 수를 출력한다.
3️⃣ 슈도 코드
BufferedReader 생성
int T = BufferedReader 입력
수를 입력받을 배열 생성
최종 값을 입력받을 배열 생성
for(T개수 입력) {
배열 입력받기
동시에 최종 값 입력받기
}
for(출력) {
최종값 입력 받기
}
count()메소드 {
조건을 처리할 로직 작성
}
4️⃣ 코드 작성
package Algorithm.DP;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class B9095 {
public static void main(String[] args) throws IOException {
//3시52분 시작
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int T = Integer.parseInt(br.readLine());
int[] arr = new int[T];
int[] sumArr = new int[T];
for (int i = 0; i <T ; i++) {
arr[i] = Integer.parseInt(br.readLine());
sumArr[i] = Count(arr[i]);
}
for (int i = 0; i <T; i++) {
System.out.println(sumArr[i]);
}
}
private static int Count(int n) {
int[] dp = new int[n + 1];
dp[1] = 1;
if (n >= 2) dp[2] = 2; //각 배열마다 그 인덱스에 맞는, 경우의 수를 넣는다.
if (n >= 3) dp[3] = 4; //각 배열마다 그 인덱스에 맞는, 경우의 수를 넣는다.
//우리는 숫자를 1,2,3만 사용해야 하니 조건은 3까지 경우의 수로 제한한다.
//그렇게 해서 쭉 각 수마다 1,2,3,으로 만들 수 있는 합의 경우의 수를 저장하고 마지막에 최종적으로 더해서 n에 맞는 총 경우의 수를 구하는 로직이다.
//i가 4인 이유는 dp배열은 이미0,1,2,3 인덱스가 꽉차 있다. 그러므로 4부터 시작한다. 이것을 사용하기 위해서 처음 배열에 n+1을 해준 것 이다.
//만약 문제에 숫자,1,2,3,4 4가지를 이용하라고 했다면 위에 if조건에 4까지 들어가고, for문은 5부터 시작했을 것이다.
for (int i = 4; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3];
//문제가 1,2,3의 활용하여 문제를 찾는 것 이기 때문에 1,2,3을 빼고 위 수들을 배열의 합을 구하는 것이다.
//배열로 하기 싫다면 재귀함수를 이용해도 된다.
}
return dp[n];
}
}
🚨 주요 로직
private static int Count(int n) {
int[] dp = new int[n + 1];
if(n>=1) {
dp[1] = 1;
}
if (n >= 2) {
dp[2] = 2;
}
if (n >= 3) {
dp[3] = 4;
}
for (int i = 4; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3];
}
return dp[n];
}
- int[] dp = new int[n + 1];
- n+1을 한 이유는, dp배열안이 n으로 만하면 0부터 시작하여 한개의 숫자가 모자르기 때문에 +1을 하여, 0을 포함한 1자리를 더 넣는다.
- if(n ≥1) { dp[1] = 1; } if (n >= 2) { dp[2] = 2; } if (n >= 3) { dp[3] = 4; }
- 위 로직은 문제가 1,2,3으로 만 n에 수 합을 만드는 경우의 수 찾는거 이기 때문에 1,2,3으로 만들 수 있는 경우의 수를 미리 찾아서 dp배열 안에 저장을 해둔다.
- 즉, dp 배열마다 그 인덱스에 맞는, 경우의 수 합을 넣는다.
- 문제에서 숫자를 1,2,3만 사용한다 했음으로, 조건은 3까지 경우의 수로 제한한다.
- 위 조건을 바탕으로 입력받는 n 마다 1,2,3,으로 만들 수 있는 합의 경우의 수를 저장하고 마지막에 최종적으로 더해서 n 에 맞는 총 경우의 수를 구하는 로직이다.
- for (int i = 4; i <= n; i++)
- for문 시작이 4인 이유는 dp배열은 이미 0,1,2,3 인덱스가 꽉 차 있다. 그러므로 4부터 시작한다. 이것을 사용하기 위해서 처음 배열에 n+1을 해준 것 이다.
- 만약 문제에 숫자,1,2,3,4 총 4개 숫자를 이용하라고 했다면 위에 if조건에 4까지 들어가고, for문은 5부터 시작했을 것이다.
🔔 젤 중요 로직 🚨
- dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3];
- 문제가 정수 1,2,3의 활용하여 경우의 수 를 찾는 것 이기 때문에 dp배열에서 1,2,3을 뺀 배열 인덱스의 값을 더하여 총 경우의 수를 구합니다.
- 배열로 하기 싫다면 재귀 함수를 이용해도 된다.
- 위 로직을 예시를 그림으로 보여드리겠습니다.
***초기상태***
dp[1] = 1
dp[2] = 2
dp[3] = 4
**n=4일때**
dp[4] = dp[3] + dp[2] + dp[1]
= 4 + 2 + 1
= 7
**n=5 일 때**
dp[5] = dp[4] + dp[3] + dp[2]
= 7 + 4 + 2
= 13
**n=6 일 때**
dp[6] = dp[5] + dp[4] + dp[3]
= 13 + 7 + 4
= 24
**n=7 일 때**
dp[7] = dp[6] + dp[5] + dp[4]
= 24 + 13 + 7
= 44
n=8 일 때
dp[8] = dp[7] + dp[6] + dp[5]
= 44 + 24 + 13
= 81
n=9 일 때
dp[9] = dp[8] + dp[7] + dp[6]
= 81 + 44 + 24
= 149
n=10 일 때
dp[10] = dp[9] + dp[8] + dp[7]
= 149 + 81 + 44
= 274
위 처럼 배열에 이미 계산되어 저장된 값을 누적하여 경우의 수를 구하는 입니다.
5️⃣ 궁금한 점
- DP(Dynamic Programming) 에 대하여 더 알아보고 싶다는 생각이 들었습니다.
- 다양한 문제를 경험하며 DP에 대한 이해도를 높이고자 함.
6️⃣ 핵심 파악하기
- 다이나믹 프로그래밍을 활용해야 한다.
- 재귀함수로도 문제를 풀 수는 있습니다만, 효율이 DP알고리즘보다 좋지 않다고 생각합니다.
728x90