- 겹치는 부분이 있어야 한다. (메모이제이션으로 중복 계산 줄이기)
- 최적 부분 구조여야 한다. 부분문제의 최적결과값을 이용하여 전체의 최적 결과를 낼 수 있는 경우.
: 동일한 계산을 반복해야 할 경우 한 번 계산한 결과를 메모리에 저장해 두었다가 꺼내 씀
= 캐싱 (Caching)
문제를 푸는데에 있어서 Top-down 방식과 Bottom-up 방식이 있다.
Top-down : 가장 큰 문제를 풀고 작은 문제들을 호출하는 방식
Bottom-up : 작은 문제들 부터 답을 찾아가는 방식
Top-down : 재귀호출
Bottom-up : 반복문
package DynamicProgramming;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class DpFibo {//24416
static int[] f;
static int dp = 0;
static int recur = 0;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
f = new int[n];
fibo(n);
recurFibo(n);
System.out.println(recur + " " + dp);
}
static int recurFibo(int n) {
// TopDown
if (n == 1 || n == 2) {
recur++;
return 1;
} else {
return (recurFibo(n - 1) + recurFibo(n - 2));
}
}
static void fibo(int n) {
// bottomUp
if (n == 0 || n == 1) {
f[n] = 1;
}
for (int i = 2; i < n; i++) {
dp++;
f[i] = f[i - 1] + f[i - 2];
}
}
}
package DynamicProgramming;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Make1 {
static Integer[] dp;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
dp = new Integer[n + 1];
dp[1] = 0;
for(int i=2; i<=n;i++){
dp[i] = dp[i-1] +1;
//1빼고 n-1 더한 것과 나눠지는 것에서 1더한 것 중 최솟값
if(i%3 == 0){
dp[i] = Math.min(dp[i], dp[i/3] +1);
}
if(i%2 == 0){
dp[i] = Math.min(dp[i], dp[i/2] +1);
}
}
System.out.println(dp[n]);
}
}
package DynamicProgramming;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class LIS2 { //11054
/*
나열된 숫자를 가지고
왼->오 방향 rdp,
오->왼 방향 ldp 배열을 만든다.
배열에는 앞서 자기 자신보다 작은 값을 담는다.
rdp + ldp - 1(자기자신 중복) 값이 최대인 값을 출력한다.
*/
static int[] arr;
static int[] rdp;
static int[] ldp;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
arr = new int[n + 1];
rdp = new int[n + 1];
ldp = new int[n + 1];
//rdp[1] = 1; ldp[n] = 1;
StringTokenizer st = new StringTokenizer(br.readLine());
for (int i = 1; i <= n; i++) {
arr[i] = Integer.parseInt(st.nextToken());
//모두 1로 초기화
rdp[i] = 1;
ldp[i] = 1;
}
System.out.println(getDp(n));
}
public static int getDp(int n) {
for (int i = 2; i <= n; i++) {
for (int j = 1; j < i; j++) {
if (arr[j] < arr[i] && rdp[j] >= rdp[i]) // rdp[j]가 나보다 작으면 안됨
rdp[i]++;
}
}
for (int i = n - 1; i >= 1; i--) { //ldp[n]은 1
for (int j = n; j > i; j--) {
if (arr[j] < arr[i] && ldp[j]>=ldp[i])
ldp[i]++;
}
}
int max = 0;
int m = n+1;
while(m-->1){
max = Math.max(max, rdp[m]+ldp[m]-1);
}
return max;
}
}
package DynamicProgramming;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class GrapeWine { //2156
static int[] arr;
static int n;
static int[] dp; //Bottomup 반복문
static Integer[] dyp; //Topdown 재귀
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
n = Integer.parseInt(br.readLine());
arr = new int[n + 1];
dp = new int[n + 1];
dyp = new Integer[n+1];
for (int i = 1; i <= n; i++) {
arr[i] = Integer.parseInt(br.readLine());
}
dp[0] = 0; dyp[0] = 0;
dp[1] =arr[1]; dyp[1] = arr[1];
if(n>1) dp[2] = arr[1]+arr[2];
if(n>1) dyp[2] = arr[1]+arr[2];
for( int i=3;i<=n;i++) {
dp[i] = Math.max(dp[i-1],Math.max(dp[i-3]+arr[i-1], dp[i-2])+arr[i]);
}
System.out.println(dp[n]);
//System.out.println(recur(n));
}
public static int recur(int n){
if(dyp[n] == null)
dyp[n] = Math.max(Math.max(recur(n-2), recur(n-3)+arr[n-1])+arr[n], recur(n-1));
return dyp[n];
}
}