Skip to content

Commit 3f0cdb0

Browse files
committed
Quartz sync: Oct 12, 2025, 5:31 PM
1 parent c5035ca commit 3f0cdb0

File tree

5 files changed

+343
-5
lines changed

5 files changed

+343
-5
lines changed

content/Computer Science/1 Foundations & Theory/Algorithms/DP/index.md renamed to content/Computer Science/1 Foundations & Theory/Algorithms/DP/_ DP with Bitmask.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ description:
33
created: 2025-05-18
44
modified: 2025-05-18
55
aliases:
6-
- "- DP with Bitmask"
76
- DP with Bitmask
87
---
98
- *어떤 것을 고를 때* 마다 *이전에 뭘 골랐나*가 중요하면, 이전에 고른 집합을 mask로 표현
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
---
2+
created: 2025/5/05 20:48:08
3+
modified: 2025/5/05 21:04:32
4+
aliases:
5+
- DP 유형
6+
---
7+
# 접근법
8+
- Q1: 최적/최대/최소/카운트 문제인가?
9+
- 의사결정 트리 그리기 (재귀 모델링)
10+
- Q2: 중복 계산이 생기나?
11+
- 메모이제이션, 타뷸레이션
12+
- Q3: 하위 문제(상태) 정의가 가능한가?
13+
- 필요한 변수파악
14+
- 상태 하나가 *작은 문제*를 완전히 대표하도록 정의
15+
- `dp[i]`가 무엇인지 정의해보기
16+
- `dp[i][j]... ` `dp[i][j][k]...`
17+
- 점화식(Transition) 도출
18+
- 의사결정 트리의 간선을 수식으로 옮기기
19+
- 택하거나, 택하지 않거나
20+
- 이동하거나, 멈추거나
21+
- 선택할 때
22+
- `min/max (dp[이전 상태] + 선택한 값, dp[지금 상태])`
23+
- 여러 선택지 중 최대/최소/최적 값 취하기
24+
- Q4: 문제 구조는?
25+
- 시간순서 or 인덱스 순 → 선형 DP
26+
- 이차원 격자 → 2D DP
27+
- 구간 분할/조합 → 구간 DP
28+
- 여러 상태 조건 → 상태 DP
29+
- 제약조건 (용량 등) → 배낭 DP
30+
- 트리/그래프 구조 → 트리 DP, 비트마스크 DP
31+
- 선형, 2D, 구간, 트리, 상태, 그리디, 케이스-분할(분기형)
32+
33+
- 최적 부분 구조, 중복 부분 문제 파악
34+
- 상태 정의
35+
- 점화식 도출
36+
- 최종 목표 설정
37+
- 경우의 수
38+
- 초기 상태 설정
39+
40+
# 선형 DP (1D)
41+
- 순서대로 누적 / 선택
42+
- 피보나치, 최대 연속합, 계단 오르기
43+
# 2D DP
44+
- 2차원에서 상태 추적
45+
- LCS, 최장 공통 부분 수열, 격자 경로
46+
47+
# 구간 DP (Interval DP)
48+
- $[i, j]$ 범위에 최적 해 존재
49+
- 사칙연산 괄호, 행렬 곱, 문자열 나누기
50+
- DP 테이블의 상삼각 영역만 주로 사용 (i <= j)
51+
- ```cpp
52+
for (int len = 2; len <= n; ++len) {
53+
for (int i = 0; i <= n - len; ++i) {
54+
int j = i + len - 1;
55+
for (int k = i; k < j; ++k) {
56+
dp[i][j] = min/max(dp[i][j], dp[i][k] + dp[k+1][j] + cost);
57+
58+
}
59+
}
60+
}
61+
62+
# 케이스-분할 (분기형) DP (Case-Split DP)
63+
- 점화식이 여러개인 경우
64+
65+
# 배낭 DP (Knapsack)
66+
- 용량/무게/자원 제한 안에서 최적 선택
67+
- 0/1 배낭, 부분합, 동전 문제
68+
69+
# 트리 DP (Tree DP)
70+
- 트리에서 하위 노드 결과 누적
71+
- 루트 포함 최대합, subtree 문제
72+
73+
74+
# DP + 상태 전이 (with state)
75+
- 단순 인덱스가 아닌 추가 상태 포함
76+
- 점프와 방향, 연속성 제한, FSM, 조합
77+
## 비트마스크 DP (Bitmask DP)
78+
- 방문 여부 등 상태를 비트로 표현
79+
- 외판원 문제(TSP), 경로 수
80+
81+
# DP + 그리디 조건
82+
- 일부 상태가 단조적일 때 최적화
83+
- LIS (이분 탐색 + DP), 회의실 문제
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
---
2+
description:
3+
aliases:
4+
- DP
5+
created: 2025-05-18
6+
modified: 2025-10-12
7+
tags:
8+
- review
9+
references: '["https":"//github.com/crapas/dp",]'
10+
---
11+
12+
- DP 문제 풀이 조건
13+
- **최적 부분 구조, 최적 하위 구조 (Optimal Substructure)**
14+
- *크기가 n인 문제*에서, 문제 해결 형태는 같지만 *n 미만의* 원소를 가지는, 더 작은 크기의 문제의 풀이법을 사용하는 것이 최적의 풀이법에 해당하면 이를 optimal substructure
15+
- *크기가 n인 문제*에서 *`k < n`인 k의* 비슷한 문제의 관점에서 정의한다는 뜻, 더 작은 원소에 대한 최적의 풀이법을 찾고, 이들을 결합해서 최종 풀이법 완성
16+
- 문제를 풀기 위한 최적의 해가, 그 하위 문제들의 최적해를 이용해 구성될 수 있을 때
17+
- 피보나치
18+
- `F(n) = F(n-1) + F(n-2)`
19+
- 하위 문제의 답을 조합하여 상위 문제의 답이 됨
20+
- **중복 부분 문제, 하위 문제의 반복 계산 (Overlapping Subproblems)**
21+
- 큰 문제를 풀기 위해 동일한 작은 문제를 반복해서 계산해야 할 때
22+
- 작은 문제를 단 한번만 풀자
23+
- 메모이제이션, 타뷸레이션
24+
- 피보나치
25+
- `F(5) → F(4) + F(3)`
26+
- `F(4) → F(3) + F(2)`
27+
- `F(3) → F(2) + F(1)`
28+
- 중복되는 연산이 있는 경우
29+
- DP 적용 체크 리스트
30+
- 문제를 같은 형태의 하위 문제로 나눌 수 있는가
31+
- 하위 문제들의 해결로 상위 문제를 해결할 수 있는가
32+
- 하위 문제의 계산이 반복되는가
33+
- 최적화, 최대화, 최소화나 어떤 작업의 경우의 수를 구하는 유형의 문제인가
34+
- 풀이 순서
35+
1. DP 적용할 수 있는지 확인
36+
2. 점화식 또는 재귀 과정 정의
37+
1. 문제를 하위 문제를 사용해 하향식으로 정의
38+
2. 맨 아래에 해당하는 '기본 경우'에 대한 답을 정의
39+
3. 종료 조건 추가
40+
3. 메모 전략을 시도
41+
4. 상향식으로 문제 풀이에 도전
42+
- 방법
43+
- 하향식
44+
- 메모이제이션 (캐쉬 기법)
45+
- 누적 (이전 계산 재사용)
46+
- 재귀로 접근
47+
- 상향식
48+
- 타뷸레이션
49+
- 점화식 필요
50+
- 반복문으로 접근
51+
- DAG에 적용 가능 (배열, 트리, 위상 정렬)
52+
- 상향식 DP가 좋지 않은 경우
53+
- combination (파스칼 삼각형)
54+
- $C(n,\;m) = C(n - 1,\;m) + C(n - 1,\;m - 1)$
55+
- ![[image-DP.png]]
56+
- 재귀는 목표한 값만 찾지만, 상향식 DP는 모든 파스칼 삼각형을 찾는다
57+
- ![[image-DP-1.png]]
58+
## 피보나치
59+
- 하향식
60+
- recursive
61+
- `dp(n - 1) + dp(n - 2)`
62+
- $O(2^{n})$
63+
- 메모이제이션
64+
- `dp_cache[n]`에 구한 값 저장
65+
- $O(n)$
66+
- 스택사용으로 살짝 성능 저하
67+
- 캐쉬 사용으로 공간 복잡도 O(n)
68+
- 상향식
69+
- $dp[1] = 1$
70+
- $dp[2] = 1$
71+
- $dp[N] = \min ( dp[i - 1] + dp[i - 2]) \quad \text{for } i = 0, 1, \dots, N )$
72+
- $O(N)$
73+
- 선형수학
74+
- 행렬로 계산시 $O(log(n))$
75+
- [[다이내믹 프로그래밍 완전 정복]] p.85
76+
## 역 사이 최소 비용 구하기
77+
- $minCost[N] = \min ( minCost[i] + cost[i][N] \quad \text{for } i = 0, 1, \dots, N )$
78+
- 상향식으로 최소 비용 갱신
79+
- [[다이내믹 프로그래밍 완전 정복]] p.87
80+
81+
## 부분 문자열 다루기
82+
- 숫자로 이루어진 문자열에서, 부분 문자열 중 앞의 절반과 뒤의 절반 숫자의 합이 같은 부분 문자열 중, 가장 긴 부분 문자열의 길이
83+
- $k = (i + j) / 2 \quad \text{mid value}$
84+
- $S(i,\; j) = S(i,\;k) + S(k + 1,\; j)$
85+
- [[다이내믹 프로그래밍 완전 정복]] p.89
86+
## 행렬에서 최소 이동 비용
87+
- $m = row \mid n = column$
88+
- $1 \leq i < m, \quad 1 \leq j < n$
89+
- $\text{mem}(i,\; j) = \min(\text{mem}(i - 1,\; j), \text{mem}(i,\; j - 1)) + \text{cost}(i,\; j)$
90+
- ![[image-DP-2.png]]
91+
- [[다이내믹 프로그래밍 완전 정복]] p.105
92+
93+
## 특정 점수에 도달하는 경우의 수 구하기
94+
- 한번에 3, 5, 10점 얻을 수 있다
95+
- 재귀의 경우
96+
- ![[image-DP-3.png]]
97+
- 상향식
98+
- $\text{for } i = 0, 1, \dots, N$
99+
- $i - 3 \geq 0 \quad \text{arr}[i] = \text{arr}[i] + \text{arr}[i - 3]$
100+
- $i - 5 \geq 0 \quad \text{arr}[i] = \text{arr}[i] + \text{arr}[i - 5]$
101+
- $i - 10 \geq 0 \quad \text{arr}[i] = \text{arr}[i] + \text{arr}[i - 10]$
102+
- $target = \text{arr}[N]$
103+
- [[다이내믹 프로그래밍 완전 정복]] p.121
104+
## 연속된 부분 배열의 최댓값 구하기
105+
- 카데인 알고리즘(Kadane's algorithm)
106+
- $\text{M}(n) = \max(\text{M}(n - 1) + \text{arr}[n], \; \text{arr}(n) )$
107+
- [[다이내믹 프로그래밍 완전 정복]] p.122
108+
## 최소 교정 비용 문제
109+
- 두 단어가 주어졌을 때, 두 단어가 똑같아 지는데 드는 교정 횟수
110+
- 2차원 DP (각 두 단어의 차원)
111+
- $1 \leq i < m, \quad 1 \leq j < n$
112+
- 첫 행, 열을 시퀀스하게 초기화
113+
- 반대 글자가 비어있다면, 교정비용은 내 현재 글자 수만큼이다
114+
- 같으면
115+
- $dp[i][j] = dp[i - 1][j - 1]$
116+
- 좌상 대각선 값
117+
- 다르면
118+
- $dp[i][j] = \min(dp[i - 1][j - 1],\; dp[i - 1][j],\; dp[i][j - 1]) + 1$
119+
- 위쪽 셀, 왼쪽 셀, 왼쪽 위 셀의 값의 최솟 값 + 1
120+
- $target = dp[m][n]$
121+
- ![[image-DP-4.png]]
122+
- [[다이내믹 프로그래밍 완전 정복]] p.130
123+
124+
## 직사각형에서 총 경로 수 구하기
125+
- M x N개의 방으로 구성된 직사각형이 있을 때, 좌상단 방에서 우하단 방까지 이동하는 모든 경로의 수
126+
- 이동 - 오른쪽, 아래 한칸 씩
127+
- 재귀
128+
- ![[image-DP-5.png]]
129+
- 지수 시간 $2^{n}$
130+
- 상향식
131+
- 2차원 DP
132+
- $dp[i][j] = dp[i - 1][j] + dp[i][j - 1]$
133+
- ![[image-DP-6.png]]
134+
- 다항 시간 $n^{2}$
135+
- [[다이내믹 프로그래밍 완전 정복]] p.137
136+
137+
## 문자열 인터리빙 확인 문제
138+
- 두 문자열 A, B의 모든 글자의 상대적인 순서가 유지 된채 섞여서 새로운 문자열 C가 만들어지면 이는 인터리빙이라 부른다
139+
- A = 'xyz'
140+
- B = 'abcd'
141+
- C = 'xabyczd' - 인터리빙
142+
- 재귀
143+
- ![[image-DP-7.png]]
144+
- 상향식
145+
- 2차원 DP (A, B)
146+
- A = 'bbca', B = 'bcc', C = 'bbcbcac'
147+
- 각 셀의 경우 (C의 현재 글자가)
148+
- A의 글자와 같고, B와 다를때
149+
- 바로 위 셀값 (B가 다르니, B에 의존적)
150+
- B의 글자와 같고, A와 다를때
151+
- 바로 왼쪽 셀값 (A가 다르니, A에 의존적)
152+
- A, B 둘다와 같을 때
153+
- 왼쪽, 위쪽 셀값 중, True가 있으면 True
154+
- A, B 둘다와 다를 때
155+
- False
156+
- ![[image-DP-8.png]]
157+
- [[다이내믹 프로그래밍 완전 정복]] p.144
158+
159+
160+
## 부분집합의 합 구하기
161+
- 0과 양의 정수로 이루어진 집합에서, 부분집합의 원소 합이 X인 것이 존재하는지
162+
- c - {3, 2, 7, 1}, X = 6
163+
- {3, 2, 1}
164+
- 재귀
165+
- 포함하는 경우 || 포함하지 않는 경우
166+
- $2^n$
167+
- 상향식
168+
- 2차원 DP
169+
- 행 - 집합 원소
170+
- 열 - 타겟 넘버 까지의 시퀀스
171+
- 중간 결과를 배열에 저장
172+
- `subsum[i][j]` 는 부분집합의 첫 (i + 1)개의 원소로 구성된 합에 대해서 합이 j$(O \leq j \leq X)$인 부분집합이 있는지에 대한 `boolean`
173+
- `subsum[i][0]` 를 $v$ 로 정의
174+
- 초기 조건
175+
- ![[image-DP-10.png]]
176+
- 첫 행은 $v$와 `j`가 똑같으면 `T`
177+
- 첫 열은 공집합이기에 항상 `T`
178+
- 두 번째 행부터, $v$의 값만큼 위 셀에서 복사
179+
- $v$의 값이 셀에 영향이 없기에
180+
- 바로 위쪽 셀이 `T`면 `T`
181+
- $(i - 1, j - v)$ 셀의 값을 $(i, j)$로 복사
182+
- ![[image-DP-11.png]]
183+
- $v$가 $X$보다 크다면 바로 위 행을 복사
184+
- 타겟 넘버보다 크기에
185+
- 아래 그림 $7$ 값인 3행은 위의 값을 그대로 복사
186+
- ![[image-DP-9.png]]
187+
- `boolean` 대신 숫자로 한다면, 그 점수에 도달하는 가짓수 도출 가능
188+
- 단 한번만 사용은 위에 행에서 `[i - 1][j - v] | [i - 1][j]`
189+
- 한번만 사용이니, 이전 행에 영향을 받는다
190+
- 무제한 사용, 순서 상관 있는 경우 (`{1, 1, 2} != {2, 1, 1}`)
191+
- 자기 행에서 `[i][j - v] + [i - 1][j]`
192+
- 무제한 사용, 순서 상관 없는 경우의 타겟($k$) 만드는 갯수
193+
- ```cpp
194+
dp[0] = 1;
195+
for (int i = 0; i < n; ++i) { // n = 동전 개수
196+
int coin = coins[i];
197+
for (int j = coin; j <= k; j++) {
198+
dp[j] += dp[j - coin];
199+
}
200+
}
201+
cout << dp[k];
202+
- [[다이내믹 프로그래밍 완전 정복]] p.152
203+
204+
## 거스름돈 최적화 (Coin Change)
205+
- 그리디로 해결 안되는 경우 ![[Greedy#^6d4b0e]]
206+
- 재귀
207+
- `coin[i]` 는 사용 가능한 종류의 동전 액면가
208+
- $\text{for } i = 0, 1, \dots, N$
209+
- $minCoins(S) = 1 + \min(minCoins(S - coin[0]), minCoins(S - coin[1]), \dots, minCoins(S - coin[N - 1]))$
210+
- 상향식
211+
- ![[image-DP-14.png]]
212+
- 1원부터 ~ $S$원 까지
213+
- 각 동전 별로 다시 순회하며 최소값 갱신
214+
- `dp[n][T]`
215+
- `dp[i][j] = dp[i - 1][j]`
216+
- `dp[i][j] += dp[i][j - coin[i]]`
217+
- `n` is coin size
218+
- `T` is target number
219+
- 경우의 수를 구할땐 숫자로 기입, 존재 여부를 구할 땐 True, False
220+
- 기저
221+
- `d[i][0]` = 1 or True
222+
- 메모리 최대 $O(T)$ 으로도 가능
223+
- 직전 만 참조함으로, 벡터 2줄로 가능 `next_dp`
224+
- [[다이내믹 프로그래밍 완전 정복]] p.171
225+
226+
## 철근 자르기
227+
- [[다이내믹 프로그래밍 완전 정복]] p.176
228+
229+
## 계단 오르기 - 2579
230+
- 2개의 1차원 dp 배열 ($A, B$)
231+
- 연속 계단 3개 불가능
232+
- $A = \text{직전 계단 사용 X}$
233+
- $B = \text{직전 계단 사용 O}$
234+
- $A_{n} = S[n] + \max(A_{n - 2},\;B_{n - 2})$
235+
- $B_{n} = S[n] + S[n - 1] + MAX(A_{n - 3},\;B_{n - 3})$
236+
237+
## LIS (최장 증가 부분 수열 길이 구하기)
238+
- ```cpp
239+
int n;
240+
cin >> n;
241+
vector<int> a(n), dp(n, 1);
242+
for (int i = 0; i < n; i++) cin >> a[i];
243+
244+
for (int i = 1; i < n; i++) {
245+
for (int j = 0; j < i; j++) {
246+
if (a[j] < a[i]) {
247+
dp[i] = max(dp[i], dp[j] + 1);
248+
}
249+
}
250+
}
251+
252+
cout << *max_element(dp.begin(), dp.end());
253+
- `dp[i]``a[i]`를 마지막 원소로 갖는 LIS의 길이
254+
- 현재 글자의, 이전 글자들 대소 비교로, dp 업데이트
255+
- 이미 왼쪽부터 dp가 정복하니 최적해 보장
256+
- $O(N^{2})$

content/Computer Science/1 Foundations & Theory/Algorithms/Greedy.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ modified: 2025-08-19
1515
- 거스름돈 최적화
1616
- 1, 5, 10, 50원 의 경우 '65원' 최적해 보장
1717
- 50, 10, 5
18-
- 1, 5, 10, 12, 50원 의 경우 '65원' 불완적 -> [[- DP]] 필요 ^6d4b0e
18+
- 1, 5, 10, 12, 50원 의 경우 '65원' 불완적 -> [[_ DP]] 필요 ^6d4b0e
1919
- 50, 12, 1, 1, 1

content/Computer Science/1 Foundations & Theory/Algorithms/index.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
description:
33
created: 2023-10-09
4-
modified: 2025-06-02
4+
modified: 2025-10-12
55
tags:
66
- cs
77
- algorithm
@@ -40,6 +40,6 @@ aliases:
4040
- [[Topological Sorting]]
4141
- [[Union-Find]]
4242
- [[Greedy]]
43-
- [[- DP]]
44-
- [[- DP 유형]]
43+
- [[_ DP|DP]]
44+
- [[_ DP 유형|DP 유형]]
4545
- [[Heap Sort, Heapify]]

0 commit comments

Comments
 (0)