<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>DP on Kelly Dev</title><link>https://kelly-chui.github.io/tags/dp/</link><description>Recent content in DP on Kelly Dev</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Mon, 10 Aug 2026 22:18:06 +0900</lastBuildDate><atom:link href="https://kelly-chui.github.io/tags/dp/index.xml" rel="self" type="application/rss+xml"/><item><title>LeetCode 1140. Stone Game II</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-1140-stone-game-ii/</link><pubDate>Mon, 10 Aug 2026 22:18:06 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-1140-stone-game-ii/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/stone-game-ii"&gt;https://leetcode.com/problems/stone-game-ii&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;돌이 일렬로 놓여 있고, 현재 &lt;code&gt;M&lt;/code&gt;일 때 &lt;code&gt;1&lt;/code&gt;개부터 &lt;code&gt;2M&lt;/code&gt;개까지 가져갈 수 있다. 돌을 가져간 뒤에는 &lt;code&gt;M&lt;/code&gt;이 &lt;code&gt;max(M, 가져간 개수)&lt;/code&gt;로 바뀐다. Alice가 항상 먼저 시작하고, Alice가 얻을 수 있는 돌의 최대 개수를 구하면 된다.&lt;/p&gt;
&lt;p&gt;현재 차례인 사람이 상대보다 얼마나 더 많이 가져갈 수 있는지로 DP를 정의할 수도 있지만, 이 문제에서는 현재 상태에서 현재 플레이어가 최대로 가져갈 수 있는 돌의 수를 저장하는 방식이 더 직관적이다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dp[i][m]&lt;/code&gt;을 &lt;code&gt;i&lt;/code&gt;번째 돌부터 시작하고 현재 &lt;code&gt;M&lt;/code&gt;이 &lt;code&gt;m&lt;/code&gt;일 때, 현재 플레이어가 얻을 수 있는 최대 돌의 수라고 하자. &lt;code&gt;suffix[i]&lt;/code&gt;는 &lt;code&gt;i&lt;/code&gt;번째 돌부터 끝까지 남은 돌의 합이다.&lt;/p&gt;</description></item><item><title>LeetCode 1510. Stone Game IV</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-1510-stone-game-iv/</link><pubDate>Mon, 10 Aug 2026 20:32:58 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-1510-stone-game-iv/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/stone-game-iv"&gt;https://leetcode.com/problems/stone-game-iv&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;돌이 &lt;code&gt;n&lt;/code&gt;개 있고, 매 턴마다 제곱수만큼의 돌을 가져간다. 마지막 돌을 가져가는 사람이 이긴다고 할 때, Alice가 이길 수 있는지 구하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dp[i]&lt;/code&gt;를 돌이 &lt;code&gt;i&lt;/code&gt;개 남았을 때 현재 차례인 사람이 이길 수 있는지로 정의한다. 어떤 제곱수 $r^2$을 가져간 뒤 상대 차례의 상태가 패배라면, 현재 플레이어는 그 선택으로 이길 수 있다.&lt;/p&gt;
&lt;p&gt;따라서 점화식은 다음과 같다.&lt;/p&gt;
&lt;p&gt;$$
dp[i] = \text{true} \quad \text{if there exists } r \text{ such that } dp[i - r^2] = \text{false}
$$&lt;/p&gt;</description></item><item><title>LeetCode 3302. Find the Lexicographically Smallest Valid Sequence</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3302-find-the-lexicographically-smallest-valid-sequence/</link><pubDate>Sat, 08 Aug 2026 21:06:44 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3302-find-the-lexicographically-smallest-valid-sequence/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/find-the-lexicographically-smallest-valid-sequence"&gt;https://leetcode.com/problems/find-the-lexicographically-smallest-valid-sequence&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;word1&lt;/code&gt;에서 인덱스를 고르고, 그 문자들로 &lt;code&gt;word2&lt;/code&gt;를 만들면 된다. 선택한 문자는 순서를 유지해야 하고, &lt;code&gt;word1&lt;/code&gt;의 문자 중 최대 하나는 다른 문자로 바꿔서 사용할 수 있다. 가능한 수열 중 인덱스가 사전순으로 가장 작은 것을 구하면 된다.&lt;/p&gt;
&lt;p&gt;앞에서부터 무조건 현재 문자가 같은지 확인하면서 고르면 되지만, 문자가 다른 위치에서 변경 기회를 바로 사용해도 뒤쪽에 남은 문자를 모두 맞출 수 있는지 확인해야 한다. 즉, 현재 위치를 선택했을 때 남은 문자의 개수가 충분해야 한다.&lt;/p&gt;</description></item><item><title>Leetcode 1406. Stone Game III</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-1406-stone-game-iii/</link><pubDate>Mon, 03 Aug 2026 12:31:05 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-1406-stone-game-iii/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/stone-game-iii"&gt;https://leetcode.com/problems/stone-game-iii&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;번호가 적힌 돌이 있고, 두 명(Alice, Bob)이 번갈아 가면서 그 돌을 1개에서 3개까지 가져갈 수 있다. 2명 다 이상적으로 플레이 했을 때, 돌에 적힌 번호를 더한 합이 더 많이 가져간 사람의 이름을 리턴하면 된다. 항상 Alice가 먼저 시작한다.&lt;/p&gt;
&lt;p&gt;약간 특이한 DP 문제이다. 점화식을 &amp;lsquo;Alice&amp;rsquo; &amp;lsquo;Bob&amp;rsquo;을 특정하지 않고 &amp;lsquo;현재 차례인 사람이 상대보다 돌을 가질 수 있는 최대 개수&amp;rsquo;로 정의해야한다.&lt;/p&gt;
&lt;p&gt;점화식은 다음과 같다.&lt;/p&gt;
&lt;p&gt;$$
dp[i] = \max \begin{cases} stoneValue[i] - dp[i+1] \\ stoneValue[i] + stoneValue[i+1] - dp[i+2] \\ stoneValue[i] + stoneValue[i+1] + stoneValue[i+2] - dp[i+3] \end{cases}
$$&lt;/p&gt;</description></item><item><title>Codeforces 455A. Boredom</title><link>https://kelly-chui.github.io/ps/2026/ps-codeforces-455a-boredom/</link><pubDate>Fri, 31 Jul 2026 20:22:51 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-codeforces-455a-boredom/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://codeforces.com/problemset/problem/455/A"&gt;https://codeforces.com/problemset/problem/455/A&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;풀이&lt;/p&gt;
&lt;p&gt;배열&lt;code&gt;a&lt;/code&gt;에서 얻을 수 있는 최대 점수를 구하는 DP 문제이다. 어떤 값 &lt;code&gt;x&lt;/code&gt;를 선택하면 &lt;code&gt;x&lt;/code&gt;만큼의 점수를 얻고, 배열에 있는 x - 1과 x + 1은 모두 제거된다.&lt;/p&gt;
&lt;p&gt;여기서 중요한 점은 같은 값을 여러 개 가지고 있다면 하나씩 선택할 이유가 없다는 것이다. &lt;code&gt;x&lt;/code&gt;를 선택하는 순간 &lt;code&gt;x - 1&lt;/code&gt;과 &lt;code&gt;x + 1&lt;/code&gt;은 모두 사용할 수 없으므로, 선택한다면 값이 &lt;code&gt;x&lt;/code&gt;인 원소는 모두 선택하는 것이 항상 이득이다.&lt;/p&gt;
&lt;p&gt;따라서 입력 배열의 순서는 의미가 없어지고, 각 숫자가 몇 번 등장하는지만 알면 된다. 값 &lt;code&gt;x&lt;/code&gt;가 &lt;code&gt;frequencies[x]&lt;/code&gt;번 등장한다면, x를 선택했을 때 얻는 점수는 &lt;code&gt;x * frequencies[x]&lt;/code&gt;이다.&lt;/p&gt;</description></item><item><title>Codeforces 189A. Cut Ribbon</title><link>https://kelly-chui.github.io/ps/2026/ps-codeforces-189a-cut-ribbon/</link><pubDate>Wed, 29 Jul 2026 10:55:29 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-codeforces-189a-cut-ribbon/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://codeforces.com/problemset/problem/189/A"&gt;https://codeforces.com/problemset/problem/189/A&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;길이가 &lt;code&gt;n&lt;/code&gt;인 리본이 하나 주어지고, 이를 &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt; 의 크기로만 조각낼 수 있을 때, 최대로 만들 수 있는 조각의 개수를 출력하는 문제이다.&lt;/p&gt;
&lt;p&gt;잘린 리본 조각의 크기가 정해져 있으므로, 그리디가 아니라 DP로 접근해야 한다. 그리디로 접근하면 마지막에 남은 리본 조각의 크기를 확정할 수 없기 때문이다. &lt;code&gt;dp[i]&lt;/code&gt;를 길이 &lt;code&gt;i&lt;/code&gt;인 리본을 조각냈을 때의 최대 조각 수로 정의하면, 점화식은 다음과 같다.&lt;/p&gt;
&lt;p&gt;$$dp[i] = \max_{x \in {a, b, c}}(dp[i - x] + 1) \quad \text{if } i \geq x \text{ and } dp[i-x] \neq -1$$&lt;/p&gt;</description></item><item><title>Leetcode 3336. Find the Number of Subsequences With Equal GCD</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3336-find-the-number-of-subsequences-with-equal-gcd/</link><pubDate>Tue, 14 Jul 2026 09:28:12 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3336-find-the-number-of-subsequences-with-equal-gcd/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/find-the-number-of-subsequences-with-equal-gcd"&gt;https://leetcode.com/problems/find-the-number-of-subsequences-with-equal-gcd&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;수열 &lt;code&gt;nums&lt;/code&gt;이 주어지고, &lt;code&gt;nums&lt;/code&gt;에서 서로 원소가 겹치지 않게 부분 수열을 두 개 만든 뒤, 각 부분 수열(이하 A, B라 함)의 GCD가 같은 경우의 수를 찾는 문제이다.&lt;/p&gt;
&lt;p&gt;만약 브루트 포스를 시도한다면, 원소의 개수 &lt;code&gt;n&lt;/code&gt;, 각 원소가 가질 수 있는 상태가 3개(부분 수열 A, 부분 수열 B, 아예 미포함)이므로, 시간 복잡도가 $O(n \times 3^n)$ 이 되는데, &lt;code&gt;nums&lt;/code&gt;의 최대 크기가 200이므로 유효한 시간 내에 해결할 수 없다.&lt;/p&gt;
&lt;p&gt;하지만 부분 수열을 점점 채워나가면서 두 부분 수열을 비교할 수 있으므로, DP를 사용하면 O(n * 부분 수열A의 최대 gcd * 부분 수열B의 gcd 최대값)이 된다. 문제의 제약조건에서 원소의 최대 크기는 200이고, GCD는 원소보다 클 수 없으므로, $O(n \times 200 \times 200)$으로 줄일 수 있다.&lt;/p&gt;</description></item><item><title>LeetCode 1301. Number of Paths with Max Score</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-1301-number-of-paths-with-max-score/</link><pubDate>Sun, 05 Jul 2026 14:30:01 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-1301-number-of-paths-with-max-score/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/number-of-paths-with-max-score"&gt;https://leetcode.com/problems/number-of-paths-with-max-score&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;2차원 그리드의 우하단에서 시작해 좌상단까지 이동하면서, 경로에 있는 숫자들의 합의 최대값과 그 최대값이 나오는 경로의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p&gt;최단 거리를 찾는 문제가 아니므로 BFS나 Dijkstra는 필요 없고, 어떻게 경로의 수를 구할지가 핵심이다. 이동 방향은 문제에서 주어져 있으므로, 각 노드에서 인접한 노드들의 값을 활용해 특정 합(&lt;code&gt;v&lt;/code&gt;)에 도달하는 경로의 개수를 구할 수 있다.&lt;/p&gt;
&lt;p&gt;이런 문제를 효율적으로 푸는 방법은 결국 DP이다. 처음에 점화식을 이렇게 만들었다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dp[r][c][v]: row = r, column = c인 노드에서 지나온 경로에 있는 칸들의 합이 v가 되는 경로의 개수.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;테스트 케이스는 통과할 수 있었지만, 실제 제출했을 때는 시간 초과가 되어서 통과하지 못했다. &lt;code&gt;v&lt;/code&gt; 차원 때문에 dp공간이 너무 커지는 것이 문제였다.&lt;/p&gt;</description></item><item><title>Programmers. 거스름돈</title><link>https://kelly-chui.github.io/ps/2025/ps-programmers-change/</link><pubDate>Sun, 03 Aug 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2025/ps-programmers-change/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://school.programmers.co.kr/learn/courses/30/lessons/12907"&gt;https://school.programmers.co.kr/learn/courses/30/lessons/12907&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;DP 문제다. 순열인지 조합인지 조심하면 쉽게 풀 수 있다. 문제에서 예시로 든 1, 2, 5원이 있을 때를 생각해보자. (5도 마찬가지지만) 2는 1의 배수이다. 따라서 순열로 하면 &amp;lsquo;3&amp;rsquo;을 만드는 경우에 1+1+1, 1+2, 2+1 이라는 세 가지 방법이 나오게 된다. 하지만 이 문제는 조합 문제이므로 중복을 제거해야한다.&lt;/p&gt;
&lt;p&gt;그러면 중복을 어떻게 제거해야 할까? 작은 동전부터 순서대로 만들면 된다. 이 방법이 조합 DP의 가장 기본적인 방법이다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;가장 작은 동전을 써서 만들 수 있는 조합을 다 만든 다음 DP 테이블에 저장한다.&lt;/li&gt;
&lt;li&gt;작은 순서대로 (오름차순으로) 조합을 더한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이런 식으로 하면 중복을 방지할 수 있다. 위 예제로 따지면 1원짜리 동전을 먼저 써서 1+1+1을 우선 만들고, 다음에 2원을 써서 1+2를 만든다. 작은 순서대로 하므로 알고리즘 상에서 2+1 같은 방법을 만들지 않는다.&lt;/p&gt;</description></item><item><title>BOJ 12852. 1로 만들기 2</title><link>https://kelly-chui.github.io/ps/2025/ps-boj-12852-make-one-2/</link><pubDate>Wed, 30 Apr 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2025/ps-boj-12852-make-one-2/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/12852"&gt;https://www.acmicpc.net/problem/12852&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;DP를 사용해서 해결했다.&lt;/p&gt;
&lt;p&gt;문제를 거꾸로 뒤집어보자. n에서 1을 가는 최단거리가 아니라, 1에서 n으로 가는 최단거리로 바꾸는 편이 편하다.&lt;/p&gt;
&lt;p&gt;이렇게 뒤집으면 개별 숫자에서 다른 숫자로 갈 수 있는 방법은 3가지가 주어진다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1 더하기&lt;/li&gt;
&lt;li&gt;2 곱하기&lt;/li&gt;
&lt;li&gt;3 곱하기&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;쉽게 점화식을 만들 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dp[i] = max(dp[i - 1], dp[i / 2], dp[i / 3]) + 1&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;하지만 경로도 트래킹 해야 하는데, 이건 각 개별 숫자에 도달하기 전에 어떤 수에서 왔는지를 저장하는 배열 하나를 만들고, 최종적으로 이 배열을 루프로 순회하거나, 재귀를 통해서 경로를 얻어낼 수 있다.&lt;/p&gt;</description></item><item><title>BOJ 2193. 이친수</title><link>https://kelly-chui.github.io/ps/2025/ps-boj-2193-pinary-number/</link><pubDate>Wed, 30 Apr 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2025/ps-boj-2193-pinary-number/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/2193"&gt;https://www.acmicpc.net/problem/2193&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;문제에서 명시적으로 두 가지 조건을 제공해준다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;0으로 시작하지 않는다.&lt;/li&gt;
&lt;li&gt;1이 연속되지 않는다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이진수라는 조건도 있으므로, 3가지 조건이 있다고 볼 수 있다.&lt;/p&gt;
&lt;p&gt;케이스를 몇개 써보면 쉽게 DP로 풀 수 있는걸 알 수 있다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;// 10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;// 100, 101&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="c1"&gt;// 1000, 1001, 1010&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;2번째 조건 때문에, 0으로 끝나는 경우에는 1을 붙일 수 있지만, 1로 끝나는 경우에는 0으로 붙일 수 없는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;DP 테이블을 다음과 같이 정의하자.&lt;/p&gt;</description></item><item><title>BOJ 2293. 동전 1</title><link>https://kelly-chui.github.io/ps/2023/ps-boj-2293-coin-1/</link><pubDate>Mon, 10 Jul 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2023/ps-boj-2293-coin-1/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/2293"&gt;https://www.acmicpc.net/problem/2293&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;DP를 사용하는 문제이다. dp 테이블의 각 인덱스가 해당 인덱스 만큼의 가치를 만들 수 있는 경우의 수 라고 하면 쉽게 풀 수 있다.&lt;/p&gt;
&lt;p&gt;동전의 가치를 &lt;code&gt;value&lt;/code&gt;라고 하면 그 동전을 하나 추가해서 &lt;code&gt;i&lt;/code&gt;만큼의 가치를 만들 수 있는 경우의 수는 &lt;code&gt;dp[i] += dp[i - value]&lt;/code&gt; 라고 할 수 있다. 따라서 하나의 가치에 대해서 동전의 종류의 수 만큼 반복문을 돌려야 한다.&lt;/p&gt;
&lt;p&gt;문제에서 주어진 또 다른 조건은 경우의 수가 2의 31제곱이 넘지 않는다는 것이다. 또한 스위프트에서는 오버플로우를 방지하기 위해 2의 31제곱이 넘어가는 수를 다 제거해줘야 한다. (최종적으로 출력할 결과가 2의 31제곱이 넘어가지 않으므로 중간에 2의 31제곱이 넘는 값은 자연스럽게 쓸모가 없는 값이 된다.)&lt;/p&gt;</description></item><item><title>BOJ 1520. 내리막 길</title><link>https://kelly-chui.github.io/ps/2023/ps-boj-1520-downhill-path/</link><pubDate>Thu, 06 Jul 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2023/ps-boj-1520-downhill-path/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/1520"&gt;https://www.acmicpc.net/problem/1520&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;dfs를 이용하면 쉽게 풀 수 있는 문제일 것 같지만, 주어지는 그래프의 크기가 커서 시간초과가 나오는 문제이다. 하지만 이러한 문제들은 중첩되는 연산이 많으므로 DP를 이용하면 시간초과 없이 해결할 수 있는 경우가 흔하다.&lt;/p&gt;
&lt;p&gt;DP의 컨셉은 다음과 같다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;그래프의 특정 칸에서 목적지로 도착하는 경우의 수는 앞선 경로에 상관없이 항상 같다.&lt;/li&gt;
&lt;li&gt;따라서 각 칸에서 목적지로 가는 경로의 수를 dp테이블에 메모이제이션 한다면 불필요한 연산을 하지 않아도 된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;따라서 점화식을 dp[x][y] = dp[x - 1][y] + dp[x + 1][y] + dp[x][y - 1] + dp[x][y + 1]로 일반화 할 수 있다. 각 항에서 탐색이 불가능한 칸((x, y)보다 높은 칸, 존재하지 않는 칸) 에 대응되는 항은 제외해야하기 때문에 엄밀히 말해서는 틀리지만, 이해하는데는 충분하다.&lt;/p&gt;</description></item><item><title>BOJ 14003. 가장 긴 증가하는 부분 수열 5</title><link>https://kelly-chui.github.io/ps/2023/ps-boj-14003-longest-increasing-subsequence-5/</link><pubDate>Wed, 01 Mar 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2023/ps-boj-14003-longest-increasing-subsequence-5/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/14003"&gt;https://www.acmicpc.net/problem/14003&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;LIS(Longest Increasing Subsequence)라고 하는 유명한 DP 문제이다. 이 문제 외에도 연계된 문제들이 많으니 1번(BOJ 11053)부터 차례대로 풀면 어느새 여기까지 풀게 된다.&lt;/p&gt;
&lt;img loading="lazy" src="https://kelly-chui.github.io/ps/2023/ps-boj-14003-longest-increasing-subsequence-5/image-002-optimized-image.webp"&gt;&lt;p&gt;이 문제들은 총 2가지 기준으로 분류된다. 첫 번째 기준은 O(n²), O(nlogn) 두 번째는 LIS 출력 여부이다. 이 중에 O(nlogn) 알고리즘을 사용하고 LIS를 직접 출력해야 하는 문제가 이 문제이다. 원래는 Swift로 작성하려 했지만, 백준의 입력시간 문제 때문에 Swift론 입력 횟수가 적은 O(n²)문제를 풀고 O(nlogn) 문제는 C++로 작성하였다.&lt;/p&gt;
&lt;p&gt;기본적인 알고리즘 콘셉트는 다음과 같다.&lt;/p&gt;</description></item></channel></rss>