
각 물건에는 무게(W)와 가치(V)가 주어진다.
배낭에는 최대 K 무게까지 물건을 넣을 수 있는데,
이때 얻을 수 있는 가치의 최댓값을 구하는 문제다.
단, 각 물건은 한 번만 넣을 수 있다.
즉, 0-1 배낭 문제(0-1 Knapsack Problem)을 그대로 구현해야 한다.
이 문제는 조합적으로 보면 모든 경우의 수를 탐색(DP 없이) 해야 하므로
DFS나 완전 탐색으로 풀면 (O(2^n)) 시간 복잡도가 되어 터진다.
그래서 다음과 같은 DP 접근을 사용한다:
dp[i]: “무게 i까지 담을 수 있을 때의 최대 가치” 뒤에서부터 갱신해야 한 물건을 여러 번 사용하는 일이 없기 때문이다.
(→ 앞에서부터 채우면 ‘무한히 재사용 가능한 배낭’ 형태가 되어버림)

dp[i]: 무게 i까지 담을 수 있을 때의 최대 가치dp[0] = 0 (나머지는 자동으로 0으로 초기화됨)각 물건 (w, v)에 대하여,
현재 용량 j를 뒤에서부터 갱신한다.
dp[j] = max(dp[j], dp[j - w] + v)
단, j >= w일 때만 가능하다.
최대 배낭 용량 k일 때의 최대 가치는
dp[k] 이다.
package A5DP.Baekjoon;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class G12865평범한배낭 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken()); // 물건 개수
int k = Integer.parseInt(st.nextToken()); // 배낭 최대 무게
int[][] arr = new int[n][2];
for (int i = 0; i < n; i++) {
st = new StringTokenizer(br.readLine());
arr[i][0] = Integer.parseInt(st.nextToken()); // 무게
arr[i][1] = Integer.parseInt(st.nextToken()); // 가치
}
int[] dp = new int[k + 1]; // dp[i]: 무게 i까지의 최대 가치
for (int i = 0; i < n; i++) {
int w = arr[i][0];
int v = arr[i][1];
for (int j = k; j >= w; j--) {
dp[j] = Math.max(dp[j], dp[j - w] + v);
}
}
System.out.println(dp[k]);
}
}