본문 바로가기

dynamic programming

(8)
82. Sum over Subsets 집합이 존재할 때 각각의 부분집합에 대해 그 집합의 부분집합의 합(Sum over Subsets)을 빠르게 계산하는 방법에 대해서 다룬다. 이 방법은 DP 테이블을 채우면서 부분집합의 합을 계산하기 때문에 SOS DP라고 불린다. 원소의 개수가 $n$인 집합의 부분집합의 개수가 $2^n$이고, SOS DP의 기본 시간복잡도가 $\Theta(2^n \cdot n)$이기 때문에 일반적으로 $n$은 $20$ 이하이다. SOS DP는 집합을 비트마스크로 표현하며, 따라서 비트필드를 이용하게 된다. 집합을 0-based로 나타내면 $0 \le p < 2^n$을 만족하는 정수 $p$는 $p$의 켜진 비트에 해당하는 원소들을 포함하는 집합을 나타내는 것으로 생각할 수 있다. 예를 들어 $0$번째, $3$번째 원소를 ..
80. Tree DP 트리에서의 동적 계획법(Tree DP)에 대해 다룬다. 트리에 대한 내용을 전혀 다루지 않은 상태에서 트리 DP를 다루는 건 순서가 뒤바뀐 느낌이지만 트리 DP가 트리와 DP 중 DP에 더 가깝기 때문에 여기서 다루었다. 트리에 대한 내용은 Chapter H에서 다루며, 기본적인 내용은 이 글을 참고하면 된다. 일반적으로 트리 DP를 시작하는 정점은 트리의 루트이며 루트 없는 트리가 주어지는 경우 임의의 정점을 하나 선택하면 되는 경우가 많다. 또한 자식 노드들의 DP 정보를 바탕으로 부모 노드의 DP 정보를 갱신하는 방법과 부모 노드의 DP 정보를 바탕으로 자식 노드의 DP 정보를 갱신하는 방법으로 구분할 수 있다. 일반적으로 전자가 더 많이 사용되는 것 같다. [연습문제] BOJ 15681. 트리와 ..
79. Bit DP 비트마스크를 이용한 동적 계획법(Bit DP)에 대해 다룬다. 일반적으로 이 유형의 문제들은 제한이 $20$ 이하로 작은 변수가 주어지는 경우가 많으며, 이 변수에 대한 각각의 상태를 비트마스크로 나타냄으로써 문제를 해결할 수 있다. 동적 계획법이 비트마스크를 이용할 경우 이때의 DP 테이블을 비트필드(Bitfield)라고도 한다. [연습문제] BOJ 1562. 계단 수 (Gold I) 더보기 현재까지 사용된 숫자의 조합과 수의 길이를 기준으로 비트필드를 채운다. 사용된 숫자의 조합은 $2^{10}$개 이하로 나오며 (아무 숫자도 사용하지 않는 경우나 사용한 숫자가 연속되지 않는 경우가 모두 제외된다. 다만 실제로 문제를 풀 때는 별로 신경쓰지 않아도 된다) $\Theta(2^{10} \cdot N)$ ..
78. Longest Common Subsequence 최장 공통 부분수열(Longest Common Subsequence, LCS)은 두 수열에 대해 정의되는 수열로, 두 수열 $a, b$가 존재하고 수열 $c$가 $a$의 부분수열이면서 $b$의 부분수열일 때 $c$를 $a$와 $b$의 공통 부분수열이라고 하고, 그런 공통 부분수열 중 가장 긴 것을 $a$와 $b$의 최장 공통 부분수열이라고 한다. 예를 들어 수열 $a$와 $b$가 다음과 같을 때 두 수열의 LCS는 $\{5, 7, 4, 6\}$이다. $$a = \{2, {\color{red}5}, 2, {\color{red}7}, 1, {\color{red}4}, 3, {\color{red}6}\}$$ $$b = \{4, {\color{red}5}, {\color{red}7}, 6, {\color{red..
77. Longest Increasing Subsequence 최장 증가 부분수열(Longest Increasing Subsequence, LIS)은 수열의 부분 수열 중 값이 오름차순으로 나오면서 가장 긴 것을 말한다. 부분 수열은 원래의 수열에서 몇 개의 원소를 제거한 뒤 남는 수열을 의미하며, 연속되지 않는 원소들이 남을 수도 있다. 예를 들어 다음과 같은 수열 $a$가 있을 때 이 수열의 LIS는 $\{2, 4, 6, 7\}$이다. $$a = \{5, {\color{Red}2}, 6, {\color{Red}4}, 8, 3, {\color{Red}6}, {\color{Red}7}\}$$ LIS의 원소들은 단조증가하므로 LIS에는 같은 원소가 두 번 이상 나타날 수 없다. 또한 한 수열에 두 개 이상의 LIS가 존재할 수도 있다. 예를 들어 수열 $a$가 다음과..
76. Prefix Sum 누적합(Prefix Sum)은 원소의 값이 변하지 않을 때 임의의 연속된 구간에 속한 원소들의 합을 빠르게 구하기 위해 사용되는 방법이다. 아이디어와 구현 모두 간단하며 다양하게 응용할 수 있다. 일반적으로 $1$차원 누적합이 많이 사용되지만 $2$차원 누적합이 사용되는 경우도 존재한다. $3$차원 이상의 누적합은 잘 사용되지 않는다. 길이가 $n$인 $1$차원 배열 $a$가 존재할 때 누적합 $s_i$는 일반적으로 다음과 같이 정의된다. $$s_0 = 0$$ $$s_i = a_i+s_{i-1}\ (1 \le i \le n)$$ 즉 $s_i$는 첫 번째 원소부터 $i$번째 원소까지의 합과 같다. $s_i$를 구했다면 임의의 연속된 구간에 속한 원소들의 합은 다음과 같이 구할 수 있다. $$\sum_{k=..
75. Dynamic Programming Intro 카테고리 E에서는 $7$가지 유형의 동적 계획법에 대해서 다룬다. 다루는 유형은 다음과 같다. 누적합(Prefix Sum) 최장 증가 부분수열(Longest Increasing Subsequence, LIS) 최장 공통 부분수열(Longest Common Subsequence, LCS) 비트필드를 이용한 동적 계획법(Bit DP) 트리에서의 동적 계획법(Tree DP) 덱을 이용한 동적 계획법(Deque DP) 부분집합의 합(Sum over Subsets, SOS DP) SOS DP는 비트필드를 이용하기 때문에 Bit DP의 일종이지만 따로 분류했다. 이 $7$가지 유형의 동적 계획법을 응용하는 방법은 매우 많으므로 많은 문제를 접하면서 익숙해지는 것이 좋다. → solved.ac tag: dp
24. Dynamic Programming & Memoization 재귀를 설명한 글의 끝부분에서 입력값이 조금만 커져도 재귀호출 횟수가 급격하게 늘어나는 문제점에 대해서 언급했는데, 이렇게 되는 이유는 중복되는 부분 문제를 계산하는 횟수가 너무 많기 때문이다. 이 문제를 풀어 보면 알 수 있지만 피보나치 수를 구하기 위해서 이 글에 나온 것처럼 코드를 짜면 함수 호출의 횟수 자체가 피보나치 수만큼 증가하기 때문에 이렇게 해서는 빠른 코드를 짤 수 없다. 하지만 중복되는 부분 문제를 살펴보면 중복되는 부분 문제에 대한 답이 항상 같기 때문에, 만약 어떤 부분 문제의 답을 계산했다면 그 계산 결과를 저장한 뒤 나중에 같은 부분 문제를 풀 때 기존에 계산한 답을 사용하면 되므로 성능을 크게 향상시킬 수 있다. 이러한 방법을 메모이제이션(Memoization)이라고 한다. (..