1/*
2 * ๋์ ํ๋ก๊ทธ๋๋ฐ (Dynamic Programming)
3 * Fibonacci, Knapsack, LCS, LIS, Edit Distance
4 *
5 * ๋ถ๋ถ ๋ฌธ์ ์ ์ต์ ํด๋ฅผ ์ด์ฉํ ๋ฌธ์ ํด๊ฒฐ ๊ธฐ๋ฒ์
๋๋ค.
6 */
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11
12#define MAX(a, b) ((a) > (b) ? (a) : (b))
13#define MIN(a, b) ((a) < (b) ? (a) : (b))
14
15/* =============================================================================
16 * 1. ํผ๋ณด๋์น (Memoization & Tabulation)
17 * ============================================================================= */
18
19long long fib_memo[100];
20int fib_computed[100];
21
22long long fibonacci_memo(int n) {
23 if (n <= 1) return n;
24 if (fib_computed[n]) return fib_memo[n];
25 fib_computed[n] = 1;
26 fib_memo[n] = fibonacci_memo(n - 1) + fibonacci_memo(n - 2);
27 return fib_memo[n];
28}
29
30long long fibonacci_tab(int n) {
31 if (n <= 1) return n;
32 long long* dp = malloc((n + 1) * sizeof(long long));
33 dp[0] = 0; dp[1] = 1;
34 for (int i = 2; i <= n; i++)
35 dp[i] = dp[i - 1] + dp[i - 2];
36 long long result = dp[n];
37 free(dp);
38 return result;
39}
40
41/* =============================================================================
42 * 2. 0/1 ๋ฐฐ๋ญ ๋ฌธ์
43 * ============================================================================= */
44
45int knapsack_01(int W, int weights[], int values[], int n) {
46 int** dp = malloc((n + 1) * sizeof(int*));
47 for (int i = 0; i <= n; i++)
48 dp[i] = calloc(W + 1, sizeof(int));
49
50 for (int i = 1; i <= n; i++) {
51 for (int w = 0; w <= W; w++) {
52 dp[i][w] = dp[i - 1][w];
53 if (weights[i - 1] <= w) {
54 int take = dp[i - 1][w - weights[i - 1]] + values[i - 1];
55 dp[i][w] = MAX(dp[i][w], take);
56 }
57 }
58 }
59
60 int result = dp[n][W];
61 for (int i = 0; i <= n; i++) free(dp[i]);
62 free(dp);
63 return result;
64}
65
66/* ๊ณต๊ฐ ์ต์ ํ */
67int knapsack_01_optimized(int W, int weights[], int values[], int n) {
68 int* dp = calloc(W + 1, sizeof(int));
69
70 for (int i = 0; i < n; i++) {
71 for (int w = W; w >= weights[i]; w--) {
72 dp[w] = MAX(dp[w], dp[w - weights[i]] + values[i]);
73 }
74 }
75
76 int result = dp[W];
77 free(dp);
78 return result;
79}
80
81/* =============================================================================
82 * 3. ์ต์ฅ ๊ณตํต ๋ถ๋ถ ์์ด (LCS)
83 * ============================================================================= */
84
85int lcs(const char* s1, const char* s2) {
86 int m = strlen(s1);
87 int n = strlen(s2);
88
89 int** dp = malloc((m + 1) * sizeof(int*));
90 for (int i = 0; i <= m; i++)
91 dp[i] = calloc(n + 1, sizeof(int));
92
93 for (int i = 1; i <= m; i++) {
94 for (int j = 1; j <= n; j++) {
95 if (s1[i - 1] == s2[j - 1])
96 dp[i][j] = dp[i - 1][j - 1] + 1;
97 else
98 dp[i][j] = MAX(dp[i - 1][j], dp[i][j - 1]);
99 }
100 }
101
102 int result = dp[m][n];
103 for (int i = 0; i <= m; i++) free(dp[i]);
104 free(dp);
105 return result;
106}
107
108/* =============================================================================
109 * 4. ์ต์ฅ ์ฆ๊ฐ ๋ถ๋ถ ์์ด (LIS)
110 * ============================================================================= */
111
112/* O(nยฒ) */
113int lis_n2(int arr[], int n) {
114 int* dp = malloc(n * sizeof(int));
115 for (int i = 0; i < n; i++) dp[i] = 1;
116
117 int max_len = 1;
118 for (int i = 1; i < n; i++) {
119 for (int j = 0; j < i; j++) {
120 if (arr[j] < arr[i] && dp[j] + 1 > dp[i])
121 dp[i] = dp[j] + 1;
122 }
123 if (dp[i] > max_len) max_len = dp[i];
124 }
125
126 free(dp);
127 return max_len;
128}
129
130/* O(n log n) */
131int lower_bound(int arr[], int n, int val) {
132 int lo = 0, hi = n;
133 while (lo < hi) {
134 int mid = (lo + hi) / 2;
135 if (arr[mid] < val) lo = mid + 1;
136 else hi = mid;
137 }
138 return lo;
139}
140
141int lis_nlogn(int arr[], int n) {
142 int* tails = malloc(n * sizeof(int));
143 int len = 0;
144
145 for (int i = 0; i < n; i++) {
146 int pos = lower_bound(tails, len, arr[i]);
147 tails[pos] = arr[i];
148 if (pos == len) len++;
149 }
150
151 free(tails);
152 return len;
153}
154
155/* =============================================================================
156 * 5. ํธ์ง ๊ฑฐ๋ฆฌ
157 * ============================================================================= */
158
159int edit_distance(const char* s1, const char* s2) {
160 int m = strlen(s1);
161 int n = strlen(s2);
162
163 int** dp = malloc((m + 1) * sizeof(int*));
164 for (int i = 0; i <= m; i++)
165 dp[i] = malloc((n + 1) * sizeof(int));
166
167 for (int i = 0; i <= m; i++) dp[i][0] = i;
168 for (int j = 0; j <= n; j++) dp[0][j] = j;
169
170 for (int i = 1; i <= m; i++) {
171 for (int j = 1; j <= n; j++) {
172 if (s1[i - 1] == s2[j - 1]) {
173 dp[i][j] = dp[i - 1][j - 1];
174 } else {
175 dp[i][j] = 1 + MIN(dp[i - 1][j - 1],
176 MIN(dp[i - 1][j], dp[i][j - 1]));
177 }
178 }
179 }
180
181 int result = dp[m][n];
182 for (int i = 0; i <= m; i++) free(dp[i]);
183 free(dp);
184 return result;
185}
186
187/* =============================================================================
188 * 6. ๋์ ๊ตํ
189 * ============================================================================= */
190
191int coin_change(int coins[], int n, int amount) {
192 int* dp = malloc((amount + 1) * sizeof(int));
193 for (int i = 0; i <= amount; i++) dp[i] = amount + 1;
194 dp[0] = 0;
195
196 for (int i = 1; i <= amount; i++) {
197 for (int j = 0; j < n; j++) {
198 if (coins[j] <= i && dp[i - coins[j]] + 1 < dp[i]) {
199 dp[i] = dp[i - coins[j]] + 1;
200 }
201 }
202 }
203
204 int result = (dp[amount] > amount) ? -1 : dp[amount];
205 free(dp);
206 return result;
207}
208
209/* =============================================================================
210 * 7. ํ๋ ฌ ์ฒด์ธ ๊ณฑ์
211 * ============================================================================= */
212
213int matrix_chain(int dims[], int n) {
214 int** dp = malloc(n * sizeof(int*));
215 for (int i = 0; i < n; i++) {
216 dp[i] = calloc(n, sizeof(int));
217 }
218
219 for (int len = 2; len < n; len++) {
220 for (int i = 1; i < n - len + 1; i++) {
221 int j = i + len - 1;
222 dp[i][j] = 2147483647;
223 for (int k = i; k < j; k++) {
224 int cost = dp[i][k] + dp[k + 1][j] + dims[i - 1] * dims[k] * dims[j];
225 if (cost < dp[i][j]) dp[i][j] = cost;
226 }
227 }
228 }
229
230 int result = dp[1][n - 1];
231 for (int i = 0; i < n; i++) free(dp[i]);
232 free(dp);
233 return result;
234}
235
236/* =============================================================================
237 * ํ
์คํธ
238 * ============================================================================= */
239
240int main(void) {
241 printf("============================================================\n");
242 printf("๋์ ํ๋ก๊ทธ๋๋ฐ (DP) ์์ \n");
243 printf("============================================================\n");
244
245 /* 1. ํผ๋ณด๋์น */
246 printf("\n[1] ํผ๋ณด๋์น\n");
247 printf(" fib(10) = %lld\n", fibonacci_tab(10));
248 printf(" fib(45) = %lld\n", fibonacci_tab(45));
249
250 /* 2. 0/1 ๋ฐฐ๋ญ */
251 printf("\n[2] 0/1 ๋ฐฐ๋ญ ๋ฌธ์ \n");
252 int weights[] = {1, 2, 3, 4, 5};
253 int values[] = {1, 6, 10, 16, 20};
254 printf(" ๋ฌด๊ฒ: [1,2,3,4,5], ๊ฐ์น: [1,6,10,16,20]\n");
255 printf(" ์ฉ๋ 8์ ์ต๋ ๊ฐ์น: %d\n", knapsack_01(8, weights, values, 5));
256
257 /* 3. LCS */
258 printf("\n[3] ์ต์ฅ ๊ณตํต ๋ถ๋ถ ์์ด (LCS)\n");
259 printf(" 'ABCDGH' vs 'AEDFHR': %d\n", lcs("ABCDGH", "AEDFHR"));
260 printf(" 'AGGTAB' vs 'GXTXAYB': %d\n", lcs("AGGTAB", "GXTXAYB"));
261
262 /* 4. LIS */
263 printf("\n[4] ์ต์ฅ ์ฆ๊ฐ ๋ถ๋ถ ์์ด (LIS)\n");
264 int arr[] = {10, 22, 9, 33, 21, 50, 41, 60, 80};
265 printf(" [10,22,9,33,21,50,41,60,80]\n");
266 printf(" O(nยฒ): %d\n", lis_n2(arr, 9));
267 printf(" O(n log n): %d\n", lis_nlogn(arr, 9));
268
269 /* 5. ํธ์ง ๊ฑฐ๋ฆฌ */
270 printf("\n[5] ํธ์ง ๊ฑฐ๋ฆฌ\n");
271 printf(" 'kitten' โ 'sitting': %d\n", edit_distance("kitten", "sitting"));
272 printf(" 'sunday' โ 'saturday': %d\n", edit_distance("sunday", "saturday"));
273
274 /* 6. ๋์ ๊ตํ */
275 printf("\n[6] ๋์ ๊ตํ\n");
276 int coins[] = {1, 5, 10, 25};
277 printf(" ๋์ : [1,5,10,25], ๊ธ์ก 30\n");
278 printf(" ์ต์ ๋์ ์: %d\n", coin_change(coins, 4, 30));
279
280 /* 7. ํ๋ ฌ ์ฒด์ธ */
281 printf("\n[7] ํ๋ ฌ ์ฒด์ธ ๊ณฑ์
\n");
282 int dims[] = {10, 30, 5, 60};
283 printf(" ์ฐจ์: 10x30, 30x5, 5x60\n");
284 printf(" ์ต์ ๊ณฑ์
ํ์: %d\n", matrix_chain(dims, 4));
285
286 /* 8. DP ๋ฌธ์ ๋ถ๋ฅ */
287 printf("\n[8] DP ๋ฌธ์ ์ ํ\n");
288 printf(" | ์ ํ | ์์ | ๋ณต์ก๋ |\n");
289 printf(" |---------------|-------------------------|-------------|\n");
290 printf(" | 1์ฐจ์ DP | ํผ๋ณด๋์น, ๊ณ๋จ ์ค๋ฅด๊ธฐ | O(n) |\n");
291 printf(" | 2์ฐจ์ DP | ๋ฐฐ๋ญ, LCS, ํธ์ง๊ฑฐ๋ฆฌ | O(nยฒ) or O(nm)|\n");
292 printf(" | ๊ตฌ๊ฐ DP | ํ๋ ฌ ์ฒด์ธ, ํฐ๋ฆฐ๋๋กฌ | O(nยณ) |\n");
293
294 printf("\n============================================================\n");
295
296 return 0;
297}