문제를 여러 개의 간단한 문제로 분리하여 부분의 문제들을 해결함으로써 최종적으로 복잡한 문제의 답을 구하는 방법이다.
톱-다운
, 바텀-업
방식으로 구현할 수 있다.D[N] = D[N-1] + D[N+2]
예제를 풀며 두가지 방식 모두 구현해보자.
백준 정수 1로 만들기
N에서 부터 1까지 내려가면서 값을 찾는 방식으로 접근하였다. 재귀함수 방식을 사용했다.
#include <iostream>
using namespace std;
int a[1000001] = {0,0,1,1};
int func(int N) {
int x;
if (N == 1 || N == 0) return 0;
else if (a[N] != 0) return a[N];
else if (N > 3) {
x = 1 + func(N - 1);
if (N % 3 == 0) x = min(x, a[N / 3] + 1);
if (N % 2 == 0) x = min(x, a[N / 2] + 1);
a[N] = x;
return x;
}
}
int main() {
int N = 0;
cin >> N;
cout << func(N);
}
1에서부터 N으로 올라가면서 값을 찾는 방식으로 접근하였다. 해당 문제의 경우 이 방식이 훨씬 빠르게 탐색이 가능하다.
재귀함수 특성상 그냥 왠만하면 반복문을 사용하는 방식이 빠르긴 하다.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int n;
cin >> n;
vector<int> vec(n + 1, 1e9);
vec[0] = 0;
vec[1] = 0;
for (int i = 1; i <= n; ++i)
{
if (i + 1 <= n)
{
if (vec[i] + 1 < vec[i + 1])
{
vec[i + 1] = vec[i] + 1;
}
}
if (i * 2 <= n)
{
if (vec[i] + 1 < vec[i * 2])
{
vec[i * 2] = vec[i] + 1;
}
}
if (i * 3 <= n)
{
if (vec[i] + 1 < vec[i * 3])
{
vec[i * 3] = vec[i] + 1;
}
}
}
cout << vec[n];
}
위가 바텀업이고 아래가 톱다운 방식이다.
확실히 재귀함수 때문에 메모리를 많이 먹는 것을 볼 수 있었다.