알고리즘/Do it! 알고리즘 코딩테스트 C++

섹션 9. 동적 계획법(Dynamic Programming)

아무키 2023. 4. 3. 09:00
반응형

동적 계획법(dynamic programming)은 복잡한 문제를 여러 개의 간단한 문제로 분리하여 부분의 문제들을 해결함으로써 최종적으로 복잡한 문제의 답을 구하는 방법을 뜻한다.

 

동적 계획법의 원리와 구현 방식

  1. 큰 문제를 작은 문제로 나눌 수 있어야 한다.
  2. 작은 문제들이 반복돼 나타나고 사용되며 이 작은 문제들의 결과값은 항상 같아야한다.
  3. 모든 작은 문제들은 한 번만 계산해 DP 테이블에 저장하며 추후 재사용할 때는 DP 테이블을 이용한다. 이를 메모이제이션(memoization) 기법이라고 부른다.
  4. 동적 계획법은 톱-다운(top-down) 방식과 바텀-업(button-up) 방식으로 구현 할 수 있다.

피보나치 수열 공식 ex) 1, 1, 2, 3, 5

D[N] = D[N -1] + D[N - 2]

 

1. 동적 계획법으로 풀 수 있는지 확인하기

   ex) 6번쨰 피보나치 = 5번째 피보나치 + 4번째 피보나치

2. 점화식 세우기

   논리적으로 전체 문제를 나누고, 전체 문제와 부분 문제간의 인과 관계를 파악하는게 중요하다.

3. 메모이제이션 원리 이해하기

   메모이제이션은 부분 문제를 풀었을 때 이 문제를 DP 테이블에 저장해 놓고 다음에 같은 문제가 나왔을 때 재계산하지 않고 DP 테이블의 값을 이용하는 것을 말한다.

 

4. 톱-다운 구현 방식 이해하기

   a. 위에서 문제를 파악해 내려오는 방식으로, 재귀 함수 형태로 코드 구현

      코드의 가독성이 좋고, 이해하기가 쉽다.

 

#include<iostream>

using namespace std;

static int D[45];

int Fibo(int num) {
	if (D[num] != -1) {
		return D[num];
	}
	return D[num] = Fibo(num - 2) + Fibo(num - 1);
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);

	int n;

	cin >> n;

	for (int i = 0; i <= n; i++) {
		D[i] = -1;
	}

	D[0] = 0;
	D[1] = 1;

	Fibo(n);

	cout << D[n];
}

 

5. 바텀-업 구현 방식

 

#include<iostream>

using namespace std;

static int D[45];

int Fibo(int num) {
	if (D[num] != -1) {
		return D[num];
	}
	return D[num] = Fibo(num - 2) + Fibo(num - 1);
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);

	int n;

	cin >> n;

	D[0] = 0;
	D[1] = 1;

	for (int i = 2; i <= n; i++) {
		D[i] = D[i - 1] + D[i - 2];
	}

	Fibo(n);

	cout << D[n];
}

바텀-업 방식이 더 안전한 방식으로, 톱-다운 방식은 재귀 함수의 형태로 구현되기 때문에 재귀의 깊이가 매우 깊어질 경우 런타임 에러가 발생할 수 있다.

 

본인에게 더 편한 방식을 찾아 선택해 사용하면 된다.

반응형