DP, 즉 다이나믹 프로그래밍(또는 동적 계획법)은 기본적인 아이디어로 하나의 큰 문제를 여러 개의 작은 문제로 나누어서 그 결과를 저장하여 다시 큰 문제를 해결할 때 사용하는 알고리즘입니다.
한 알고리즘에 국한된 것이 아닌, 알고리즘을 설계하는 방법이나 접근 방식을 나타냅니다.
문제 풀이 방식의 하나라고 볼 수 있습니다. 이를 알고리즘 설계 기법이라고 합니다.
🚩 알고리즘 설계 기법
- 모든 경우의 수를 구하는 완전 탐색을 하면 가장 좋겠지만, 시간 상으로 메모리 상으로 최적화가 가장 중요합니다. 그래서 다양한 설계 기법을 도입하는데요.
- 예를 들어, 분할 정복, 그리디, 백트래킹이 그 예시가 됩니다.
그러면 DP는 왜 쓰고, 언제 쓰는지 알아야겠죠?
재귀적 용법과 굉장히 흡사한 DP는 단순한 재귀 사용보다, 작은 문제들이 여러번 사용되어 비효율적인 방식을 보완합니다.
가장 흔하게 재귀를 사용하는 것은 피보나치 수를 예시로 들 수 있습니다.
f(10)을 구하기 위해서는, f(9)도 구해야 하고, f(8)도 구해야 합니다.
또한 f(9)를 구하기 위해서 더 많은 재귀함수를 호출해야합니다.
하지만 이미 수행된 작업에 대해서 기록(Memoization)을 해둔다면, 또 다시 계산할 필요 없이 중복된 값을 구할 수 있습니다.
DP는 주로 중복되는 부분이 반복적으로 나타날 때, 사용이 가능하다.
따라서, 중복되는 부분에 대해서 구해두고, 기록(Memoization)해두고, 추후 중복되는 부분이 나오면 그 값을 가져와 사용할 수 있어야 하는데, 중복되는 부분이 없다면 DP를 사용할 수 없다.
부분 문제의 최적 결과 값을 사용해 전체 문제의 최적 결과를 낼 수 있는 경우를 이야기 합니다.
어쨌든, 작은 문제로 분할하여 문제를 푸는데, 최적의 결과를 도출했을 때, 전체 문제에서도 최적의 결과를 낼 수 있습니다.
그럴때 최단 거리로 가는 방법을 고민한다고 했을때,
[서울 → 대구]의 최단 거리 + [대구 → 부산]의 최단 거리 를 구하면 [서울 → 부산]의 최단 거리를 구할 수 있다. 이 처럼, 부분 문제에서의 최적 결과 값이 전체 문제의 최적 결과를 낼 수 있는 경우가 되어야 DP를 사용할 수 있습니다.
DP는 알고리즘 설계 기법이기때문에, 한 분야에 국한되지 않고, 다양한 곳에 사용될 수 있습니다.
그래서 이 문제를 DP로 풀 수 있는지 알아내는 것이 중요합니다.
DP 문제를 풀 때는 다음과 같은 과정을 거치게 됩니다.