백엔드개발/Baekjoon

[Baekjoon] 9095 1,2,3 더하기 - JAVA

aaahyunseo 2025. 1. 4. 17:19

문제

정수 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

📝 제출 답안

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();

        int t = Integer.parseInt(br.readLine());
        for (int i = 0; i < t; i++) {
            int n = Integer.parseInt(br.readLine());
            int[] dp = new int[11];
            dp[1] = 1;
            dp[2] = 2;
            dp[3] = 4;

            for (int j = 4; j <= n; j++){
                dp[j] = dp[j-1] + dp[j-2] + dp[j-3];
            }
            sb.append(dp[n]).append("\n");
        }
        System.out.println(sb);
    }
}

 

이번 문제는 다이나믹 프로그래밍(DP)을 사용하는 문제였다.

 

효율성을 위해서 BufferedReader와 StringBuilder를 사용하여 입력과 문자열 출력을 담당한다.

테스트 케이스 개수 대로 입력을 받아 결과를 sb에 누적한다.

 

먼저 숫자 1을 만드는 방법(dp[1])은 1가지 이다. (1)

숫자 2를 만드는 방법(dp[2])은 2가지 이다. (1+1, 2)

숫자 3을 만드는 방법(dp[3])은 4가지 이다. (1+1+1. 1+2, 2+1, 3)

숫자 4를 만드는 방법(dp[4])은 7가지로 숫자1, 2, 3을 만드는 방법의 수를 합한 것과 같다.

 

즉 dp[j]를 구하는 점화식은 dp[j] = dp[j-1] + dp[j-2] + dp[j-3] 이다.

이 점화식은 1,2,3 만을 사용하여 특정 숫자를 만드는 경우의 수를 나타낸다.

 

문제에서 " n은 양수이며 11보다 작다." 라고 했기 때문에 배열의 크기를 11로 지정해준다.

 

이 문제는 1,2,3의 합으로 숫자를 표현하는 경우의 수를 동적 프로그래밍으로 계산하는 것이다. 점화식을 사용하여 이전 값들을 기반으로 현재 값을 계산한다.

 


🪄 동적 프로그래밍(Dynamic Programming, DP)

동적 프로그래밍은 복잡한 문제를 작은 하위 문제로 나누어 해결하고, 그 결과를 저장하여 같은 하위 문제를 반복적으로 계산하지 않도록 최적화하는 알고리즘 설계 기법이다. (예: 피보나치 수열 F(n) = F(n-1) + F(n-2) )

 

 

동적 프로그래밍의 핵심 원리

1. 중복되는 하위 문제 (Overlapping Subproblems)

문제를 풀기 위해 같은 하위 문제가 여러 번 반복해서 계산되는 경우, 이를 저장하고 재활용하여 효율적으로 해결한다.

2. 최적 부분 구조 (Optimal Substuructure)

큰 문제의 최적해가 작은 하위 문제들의 최적해로 구성될 수 있어야 한다.

 

 

동적 프로그래밍의 구현 방식

1. Memoization

  • 탑다운 방식 : 재귀를 사용하여 하위 문제를 푸는 과정에서 결과를 저장한다.
  • 저장된 값을 활용하여 동일한 하위 문제를 다시 계산하지 않는다.

2. Tabulation

  • 바텀업 방식 : 작은 문제부터 차례로 해결하며 테이블에 결과를 저장한다.
  • 계산 순서를 정해 반복문을 사용한다.

 

[예시]

 

일반 재귀

public int fib(int n) {
    if (n <= 1) return n;
    return fib(n - 1) + fib(n - 2);
}

 

일반 재귀는 같은 값이 여러 번 계산되므로 비효율적.

 

DP1. Memoization

public int fib(int n, int[] memo) {
    if (n <= 1) return n;
    if (memo[n] != 0) return memo[n];
    return memo[n] = fib(n - 1, memo) + fib(n - 2, memo);
}

 

DP2. Tabulation

 

public int fib(int n) {
    if (n <= 1) return n;
    int[] dp = new int[n + 1];
    dp[0] = 0; dp[1] = 1;
    for (int i = 2; i <= n; i++) {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    return dp[n];
}

 

 

 

동적 프로그래밍의 사용 이유

1. 효율성 증가

반복적인 계산을 제거하여 시간 복잡도를 크게 줄일 수 있다.

2. 명확한 구조

문제를 작은 단계로 나누어 해결하므로 논리적으로 이해하기 쉽다.

 

 

동적 프로그래밍의 사용 문제 유형

1. 최단 경로 문제 (다익스트라, 플로이드-워셜 등)

2. 부분합 문제

3. 문자열 문제 (최장 공통 부분 문자열)

4. 게임 이론 (최적 전략 계산)

 

제출 현황

 

'백엔드개발 > Baekjoon' 카테고리의 다른 글

[Baekjoon] 1260 DFS와 BFS - JAVA  (0) 2025.01.07
[Baekjoon] 1003 피보나치 수열 - JAVA  (0) 2025.01.06
[Baekjoon] 11723 집합 - JAVA  (1) 2025.01.03
[Baekjoon] 18110 solved.ac - JAVA  (0) 2025.01.02
[Baekjoon] 28702 FizzBuzz - JAVA  (0) 2025.01.01