반응형
Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
Tags
- 멀티태스킹
- 백트래킹
- Comparator
- 오버로딩
- java
- Comparable
- 둘만의 암호 자바
- BFS
- 프로그래머스
- 혼공얄코
- 자바의 정석
- hackerrank
- localtime
- spring security
- over()
- SQL Mapper
- 오블완
- 프로그래머스 둘만의 암호
- 둘만의 암호
- LocalDate
- Arrays
- spring security 설정
- 티스토리챌린지
- 리눅스
- greedy
- 분할정복
- 분할정복 알고리즘
- 멀티프로세싱
- 자바의정석
- 오버라이딩
Archives
- Today
- Total
쉽게 쉽게
[알고리즘] DP(동적 프로그래밍)란? (백준 11050, 1010) 본문
반응형
📌 핵심 요약
- DP는 큰 문제를 작은 문제로 쪼개고, 이미 계산한 값을 저장해 재사용하는 알고리즘 기법입니다.
- 파스칼의 삼각형은 이항 계수를 DP로 표현한 대표적인 예시입니다.
- 문제풀이 과정에서 이항계수의 로직을 재귀 또는 DP를 활용하여 풀이했을 때, 차이점을 알아보려고 합니다.
- DP를 활용해 백준 11050 · 1010번을 오버플로우 없이 효율적으로 풀 수 있습니다.
1 DP(동적 프로그래밍)란?
DP(Dynamic Programming, 동적 프로그래밍)는 큰 문제를 작은 부분 문제로 쪼개어, 이미 계산한 값을 배열에 저장해두고 필요할 때 다시 꺼내 쓰는 알고리즘 설계 기법입니다.
한 줄 정의
"이미 푼 문제는 다시 풀지 않는다" — 중복 계산을 없애 효율을 극적으로 높이는 기법DP의 두 가지 핵심 조건
| 조건 | 설명 | 예시 |
|---|---|---|
① 중복 부분 문제Overlapping Subproblems |
같은 작은 문제가 반복해서 등장한다 | C(5,2)를 구할 때 C(4,1)이 여러 번 필요 |
② 최적 부분 구조Optimal Substructure |
큰 문제의 답이 작은 문제의 답으로 구성된다 | C(5,2) = C(4,1) + C(4,2) |
재귀 vs DP
일상에서의 예시로 설명하면, 매번 1+1+1+1+1을 계산하는 대신 "5"라는 답을 메모지에 적어두고 꺼내 쓰는 것이 바로 DP입니다. 프로그래밍에서는 이 메모지 역할을 배열(dp[ ])이 합니다.
재귀만 쓰면 느린 이유
피보나치를 일반 재귀로 구현하면 fib(40)을 구하기 위해 같은 값을 수억 번 다시 계산합니다. DP를 쓰면 단 40번의 연산으로 끝납니다.2 파스칼의 삼각형이란?
백준 11050 · 1010번은 이항계수를 활용한 문제들로 이는 파스칼의 삼각형을 이용해 풀이할 수 있습니다.
파스칼의 삼각형은 이항 계수를 삼각형 모양으로 배열한 수표로 DP의 대표적인 예시입니다.
N번째 행의 K번째 값이 정확히 C(N, K)와 같습니다.

핵심 규칙 2가지
점화식
dp[i][j] = dp[i-1][j-1] + dp[i-1][j]바로 위 왼쪽 + 바로 위 오른쪽. 양쪽 끝은 항상 1.
| 규칙 | 수식 | 설명 |
|---|---|---|
| 양쪽 끝은 항상 1 | C(N,0) = C(N,N) = 1 |
어떤 행이든 첫째·마지막 값은 1 |
| 나머지 = 위 두 값의 합 | C(N,K) = C(N-1,K-1) + C(N-1,K) |
바로 위 왼쪽 + 바로 위 오른쪽 |
이항 계수와의 관계
파스칼의 삼각형을 미리 계산해두면 C(N, K)를 dp[N][K] 한 번의 배열 조회로 O(1)에 바로 얻을 수 있습니다. 예를 들어 C(5,2) = 10은 5번째 행 3번째 값으로 바로 확인됩니다.
3 파스칼의 삼각형을 DP로 구현하기
점화식 dp[i][j] = dp[i-1][j-1] + dp[i-1][j]를 그대로 코드로 옮기면 됩니다.
30×30 배열에 미리 전처리해두면 이후 조회는 dp[n][k] 한 줄로 끝납니다.
static int[][] dp = new int[30][30];
static void precompute() {
for (int i = 0; i < 30; i++) {
dp[i][0] = dp[i][i] = 1; // 양쪽 끝은 항상 1
for (int j = 1; j < i; j++) {
dp[i][j] = dp[i-1][j-1] + dp[i-1][j];
// ↑ 위 왼쪽 ↑ 위 오른쪽
}
}
}
왜 30×30 배열인가?
백준 1010번의 제약이 N, M < 30이기 때문입니다. 미리 전처리해두면 이후 조회는 dp[m][n] 한 줄로 O(1)에 끝납니다.4 백준 11050 — 이항 계수 1
BOJ #11050
이항 계수 1
자연수 N과 정수 K가 주어졌을 때 이항 계수 C(N, K)를 구하시오.
풀이 과정
- 파스칼의 삼각형을 11×11 배열에 전처리한다.
- N과 K를 입력받는다.
dp[N][K]를 출력한다.
import java.util.Scanner;
public class Main {
static int[][] dp = new int[11][11];
static void precompute() {
for (int i = 0; i <= 10; i++) {
dp[i][0] = dp[i][i] = 1;
for (int j = 1; j < i; j++)
dp[i][j] = dp[i-1][j-1] + dp[i-1][j];
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
precompute();
int n = sc.nextInt();
int k = sc.nextInt();
System.out.println(dp[n][k]);
}
}
입출력 예시
| 입력 | 출력 | 계산 |
|---|---|---|
5 2 |
10 |
C(5,2) = 5!/(2!·3!) = 10 |
10 5 |
252 |
C(10,5) = 252 |
5 백준 1010 — 다리 놓기
BOJ #1010
다리 놓기
서쪽 N개 사이트를 동쪽 M개 사이트에 겹치지 않게 연결하는 경우의 수 = C(M, N)
풀이 과정
- 파스칼의 삼각형을 30×30 배열에 전처리한다.
- 테스트케이스 T를 입력받는다.
- 각 케이스에서 N, M을 입력받아
dp[M][N]을 출력한다.
왜 C(M, N)인가?
다리가 겹치지 않으려면 동쪽 M개 중 N개를 순서를 유지하며 선택해야 합니다. 선택 후 위에서부터 1:1 매핑하면 자동으로 교차하지 않으므로 답은 조합 C(M, N)이 됩니다.import java.util.Scanner;
public class Main {
static int[][] dp = new int[30][30];
static void precompute() {
for (int i = 0; i < 30; i++) {
dp[i][0] = dp[i][i] = 1;
for (int j = 1; j < i; j++)
dp[i][j] = dp[i-1][j-1] + dp[i-1][j];
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
precompute();
int t = sc.nextInt();
while (t-- > 0) {
int n = sc.nextInt();
int m = sc.nextInt();
System.out.println(dp[m][n]); // C(M, N)
}
}
}
입출력 예시
| 입력 | 출력 | 계산 |
|---|---|---|
2 2 |
1 |
C(2,2) = 1 |
1 5 |
5 |
C(5,1) = 5 |
13 29 |
67863915 |
C(29,13) |
6재귀 / DP 풀이 비교 정리
재귀 풀이 예시
import java.util.Scanner;
public class Main {
// n! 을 반환하는 팩토리얼 함수
static int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int K = sc.nextInt();
// C(N, K) = N! / (K! * (N-K)!)
int result = factorial(N) / (factorial(K) * factorial(N - K));
System.out.println(result);
}
}
| 구분 | 팩토리얼 방식 | 파스칼 삼각형 (DP) |
|---|---|---|
| 오버플로우 | 위험 (N≥13) | 안전 |
| 조회 속도 | O(N) — 매번 계산 | O(1) — 배열 조회 |
| 전처리 비용 | 없음 | O(N²) — 1회만 |
| 다중 쿼리 | 느려질 수 있음 | 매우 빠름 |
| 추천 상황 | N ≤ 10, 단일 쿼리 | N ≥ 13 또는 다중 쿼리 |
결론
이항 계수 문제는 파스칼의 삼각형 DP로 구현하는 것이 안전하고 확장성이 좋습니다. 다중 테스트케이스 문제에서는 미리 전처리하는 방식이 필수입니다.팩토리얼 방식 사용 시 주의
N이 13 이상이면 int는 물론 long으로도 중간 계산 값이 오버플로우됩니다. 반드시 파스칼 DP 또는 분할 계산 방식을 사용하세요.| 잘못된 내용이 있다면 지적부탁드립니다. 방문해주셔서 감사합니다. |

반응형