예시 : 아주 많은 동전 더미 속에 1개의 가짜 동전이 섞여 있다. 이 가짜 동전은 매우 정교하게 만들어져 누구도 눈으로 가짜인지를 식별할 수 는 없지만, 무게가 정상적인 동전보다 약간 가볍다. 1개의 양팔 저울만을 사용해 이 가짜 동전을 최소한의 저울질로 찾아낼 수 있는 방법은 무엇인가?
Solution1 : 매 시행마다 양팔 저울에 동전 한개씩 올려서 비교한다.
Solution2 : 매 시행마다 양팔 저울에 두개의 그룹으로 나눈 동전 더미를 올려서 비교한다.
Solution3 : 두개의 그룹으로 나누는 것이 아닌, 저울에 올라가지 않는 동전더미 그룹을 하나 더 만들어 총 세개의 그룹으로 나눈다.
< N개 수의 합 구하기 >
< 거듭제곱 프로그래밍 >
double power(double x, int n)
{
if (n==0) return 1;
else if ((n%2)==0) # 짝수일 경우
return power(x*x,n/2);
else return x*power(x*x,(n-1)/2); # 홀수일 경우, x^25=x^12*x^12*x
}
- 하위 문제 간 겹침이 발생하지 않을 경우 분할정복이 효율적
- 하위 문제 간 겹침이 발생하는 경우 DP가 효율적
- DP와 분할정복의 가장 큰 공통점은 가장 간단한 문제로 분할 한다는 점이지만, 가장 큰 차이점은 DP는 가장 작은 문제를 풀고 memoization을 통해 결과를 기록하고 기록한 결과를 이용하여 다음 큰 문제를 푼다는 점이다. 분할정복은 가장 간단한 문제를 풀고 재귀를 이용하여 다음 큰 문제를 푼다.
피보나치 수열 (분할정복)
int fib(int n){
if (n<=0) return 0;
else if (n==1) return 1;
else return fib(n-1) + fib(n-2); }
피보나치 수열 (DP, Bottom-up)
int fib(int n){
int map[n+1]; map[0]=0; map[1]=1;
if (n<=0) return map[0];
else if (n==1) return map[1];
else{
for (i=2; i<=n; i++)
map[n]= map[n-1]+map[n-2] # "기억하기"
return map[n]; }}
피보나치 수열 (DP, Top-Down)
int map[n+1]; map[0]=0; map[1]=1;
int fib(int) {
if( map(n) is ready) return map[n];
else{
map[n]=fib[n-1] + fib[n-2];
return map[n]; }}
📒 보통은 Top-Down 방식이든 Bottom-Up 방식을 사용하든 문제를 푸는데 지장이 없지만 상황에 따라 더 효율적인 방식이 존재한다.
< 동전 거스름돈 문제 >
📒 나는 DP문제의 경우 차트(표)를 하나 그려서 나올 수 있는 모든 경우의 수를 적어보고, 규칙을 찾아내어 점화식을 생성한다.
너무 멋있어요