DP는 하나의 문제를 여러 개의 하위 문제로 나눠 계산한 뒤, 이 결과를 재사용하여 문제를 효율적으로 해결하는 알고리즘 기법입니다. 동일한 하위 문제가 여러 번 반복되는 경우, 계산 결과를 테이블에 저장해 중복 계산을 피합니다.
DP는 주로 최적화 문제 풀이와 관련 있습니다. 여러 개의 해답 중 최대(최소) 값을 구하거나, 이 때 최적의 해답을 계산하는 데 사용됩니다.
f(4) → f(3) → f(2) …step1. 구조를 분석하기 (Top-Down)
step2. 최적 값을 재귀식으로 정의하기
step3. 상향식으로 최적값 계산하기 (Bottom-Up)
(필요한 경우 )step4. 최적의 해답 계산하기(Reconstruct)
step3의 최적 값을 계산하는 과정에서 발생하는 정보를 이용하여 구합니다.
크기가 2 X N 인 직사각형의 판이 주어졌을 때, 이 판을 2 X 1 타일로 채우는 경우의 수를 구하는 문제입니다.

step1. 구조 분석하기 (Top-Down)

step2. 최적 값을 재귀식으로 정의하기
C(n) : 가로가 n인 판을 채우는 방법의 수라고 정의한다.
step3. 상향식으로 최적값 계산하기(Bottom-Up)
C(n) → C[n]C[n] = C[n-1] + C[n-2]로 구하면 된다.#include <iostream>
#include <vector>
using namespace std;
int tabulation(int n)
{
if (n == 1 || n == 2) return n;
vector<int> vec(n+1, 0);
vec[1] = 1;
vec[2] = 2;
for (int i = 3; i <= n; i++)
{
// 차례대로 값 구하기
vec[i] = vec[i-1] + vec[i-2];
}
return vec[n];
}
int memoization(vector<int>& vec, int n)
{
// 값이 테이블에 존재하는 경우
if (vec[n] != -1) return vec[n];
// 값이 테이블에 없어 구해야 하는 경우
if (n == 1 || n == 2) return vec[n] = n;
return vec[n] = memoization(vec, n-1) + memoization(vec, n-2);
}
int main(void)
{
int n; cin >> n;
cout << tabulation(n) << "\n";
vector<int> memo(n+1, -1);
cout << memoization(memo, n) << "\n";
}

동전의 종류가 { 1원, 5원, 10원, 21원, 25원 } 로 5 개일 때, k원을 만드는 최소 동전 개수를 구한 뒤, 이 때 동전 조합을 구하라.
step1. 구조를 분석하기 (Top-Down)

step2. 최적 값을 재귀식으로 정의하기

C(k) : k원을 구성하기 위한 최소 동전의 개수라고 정의한다.step3. 상향식으로 최적값 계산하기 (Bottom-Up)

minCoinCounts[k] 배열은 k원을 만들기 위한 최소 동전의 개수를 저장한다.(필요한 경우)step4. 최적의 해답 계산하기(Reconstruct)
lastUsedCoin 에 사용된 금액 기록한다. 42원이 2개의 동전으로 구성할 수 있어 최적 값이었다. (63 - 21 = 42) 즉, 21원짜리 동전을 사용해서 42원에 접근했으므로, lastUsedCoin[63] = 21이 된다. 63원을 최소 동전 개수로 구성하기 위해 마지막으로 사용한 동전이 21원 짜리 동전임을 의미한다.
이렇게 작성된 표로, 최적 해답를 구할 수 있다.

17원을 구성하는 최소 동전 조합을 구하려고 한다. 
lastUsedCoin[17]이 5이므로, 5원 짜리 동전이 사용됐음을 알 수 있다. 이렇게 역추적을 시작하면

12원을 구성하기 위해선 10원 짜리 동전이 사용됐으며

2원 을 구성하기 위해선 1원 짜리 동전이 총 2개 쓰였음을 알 수 있다.
최종적으로 17원 을 구성하는 최소 동전 조합은 [ 1원, 1원, 5원, 10원 ] 총 4개가 필요하다.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 사용할 동전 단위
const int coins[] = { 1, 5, 10, 21, 25 };
int totalAmount;
void tabulation()
{
int coinCount = sizeof(coins) / sizeof(coins[0]);
// 각 금액별 최소 동전 수를 저장하는 배열
vector<int> minCoins(totalAmount + 1, 0);
// 각 금액을 만들기 위해 마지막으로 사용된 동전 저장
vector<int> lastUsedCoin(totalAmount + 1, 0);
for (int amount = 1; amount <= totalAmount; ++amount)
{
int minCount = amount; // 최악의 경우 모두 1원짜리 사용
int chosenCoin = 1; // 기본값으로 1원 선택
// 사용 가능한 동전 중에서 최소 동전 수를 만드는 조합 탐색
for (int i = 0; i < coinCount; ++i)
{
if (coins[i] > amount) continue;
int candidate = minCoins[amount - coins[i]] + 1;
if (candidate < minCount)
{
minCount = candidate;
chosenCoin = coins[i];
}
}
minCoins[amount] = minCount;
lastUsedCoin[amount] = chosenCoin;
}
// 결과 출력: 최소 개수 및 사용된 동전 목록
cout << "최소 동전 개수: " << minCoins[totalAmount] << "\n";
cout << "동전 조합: ";
int remaining = totalAmount;
while (remaining > 0)
{
cout << lastUsedCoin[remaining] << " ";
remaining -= lastUsedCoin[remaining];
}
}
int main()
{
cin >> totalAmount; // 금액 입력 받기
tabulation();
return 0;
}