하나의 문제를 단 한번만 풀게 하는것
가정1. 큰 문제를 작은 문제로 나눌 수 있다.
가정2. 작은 문제에서 구한 정답은 그것을 포함하는 큰 문제에서도 동일하다.
피보나치 수열의 예제
#include <stdio.h>
int dp(int x) {
if(x ==1) return 1;
if(x ==2) return 1;
return p(x -1) + dp(x -2);
}
int main(void){
printf("%d", dp(40));
}
#include <stdio.h>
int d[100];
int dp(int x) {
if(x ==1) return 1;
if(x ==2) return 1;
if(d[x] !=0) return d[x];
return d[x] = dp(x -1) + dp(x -2);
}
int main(void){
printf("%d", dp(40));
}
이미 구한 값을 배열에 저장하여 그 값을 불러 냄
타일링
1.백준 11726
- 점화식을 세운다
d[x] = d[x-1] + d[x-2]
x=1 일때 경우의 수 : 1
x=2 일때 경우의 수 : 2
#include <stdio.h>
int d[1001];
int dp(int x){
if(x ==1) return 1;
if(x ==2) return 2;
if(d[x]!=0) return d[x];
return d[x] = (dp(x - 1) +dp(x - 2)) % 10007;
}
int main(void){
int x;
scanf("%d", &x);
printf("%d", dp(x));
}
2.백준 11727
d[x] = d[x-1] + 2*d[x-2]
x=1 일때 경우의 수 : 1
x=2 일때 경우의 수 : 3
#include <stdio.h>
int d[1001];
int dp(int x){
if(x ==1) return 1;
if(x ==2) return 3;
if(d[x]!=0) return d[x];
return d[x] = (dp(x - 1) +2 *dp(x - 2)) % 10007;
}
int main(void){
int x;
scanf("%d", &x);
printf("%d", dp(x));
}
3.백준 2133
d[x] = 3*d[x-2] + 2*d[x-2] +2*d[x-4]+....2*d[0]
x=1 일때 경우의 수 : 0
x=2 일때 경우의 수 : 3
점화식을 세울 때 그 식에 예외는 없는지 확인한다.
#include <stdio.h>
int d[1001];
int dp(int x){
if(x ==0) return 1;
if(x ==1) return 0;
if(x ==2) return 3;
if(d[x] !=0) return d[x];
int result = 3*dp(x-2);
for(int i=3; i<=x;i++){
if(i % 2 ==0){
result += 2*dp(x-i);
}
}
return d[x] = result;
}
int main(void){
int x;
scanf("%d", &x);
printf("%d", dp(x));
}
3.백준 14852
x=1 일때 경우의 수 : 2
x=2 일때 경우의 수 : 3
--------------------------
x=3 일때 경우의 수 : 2
x=4 일때 경우의 수 : 2
.....
d[x] = 3*d[x-2] + 2*d[x-1] + (d[x-3]*2 + d[n-4]*2 ....2*d[0])
--------------------------
d[x] = d[x-1]*2 + d[x-2]*3 + (d[x-3]*2 + d[x-4]*2 + ....d[0]*2)
#include <stdio.h>
int d[1000001];
int dp(int x){
if(x ==0) return 1;
if(x ==1) return 2;
if(x ==2) return 7;
if(d[x] !=0) return d[x];
int result = 3*dp(x-2) + 2*dp(x-1);
for(int i=3; i<=x;i++){
if(i % 2 ==0){
result += (2*dp(x-i)) % 1000000007;
}
}
return d[x] = result % 1000000007;
}
int main(void){
int x;
scanf("%d", &x);
printf("%d", dp(x));
}
시간 초과 발생 = 효율적이지 않은 알고리즘임
2차원 dp 기법을 사용하여 해결 할 수 있다.
#include <stdio.h>
long long int d[1000001][2];
long long int dp(int x){
d[0][0]=0;
d[1][0]=2;
d[2][0]=7;
d[2][1]=1;
for(int i=3;i<=x;i++){
d[i][1] = (d[i-1][1] + d[i-3][0]) % 1000000007;
d[i][0] = (3*d[i-2][0] + 2*d[i-1][0] + 2*d[i][1]) % 1000000007;
}
return d[x][0];
}
int main(void){
int x;
scanf("%d", &x);
printf("%lld", dp(x));
return 0;
}
dp기법을 사용할 때 배열을 이용해 그 값들을 저장하는 방법을 잘 숙지 하고 더 나아가서 2차원 dp의 개념과 사용법을 숙지 할 필요가 있음.
또한 점화식을 제대로 작성하는 방법과 종료조건의 수를 수학적으로 잘 고려해야 할 것으로 보임.
'알고리즘공부' 카테고리의 다른 글
에라토스테네스의 체 (0) | 2020.03.20 |
---|---|
크루스칼 알고리즘(Kruskal's Algorithm) (0) | 2020.03.01 |
합집합 찾기(Union-find) (0) | 2020.03.01 |
[자료구조] 스택(Stack)과 큐(Queue) (0) | 2020.02.25 |
계수정렬(Counting Sort) (0) | 2020.02.24 |