문제
유명한 01 배낭(01 Knapsack) 문제.
배낭 문제는 물건을 쪼개는게 가능한 Fraction Knapsack과
물건을 쪼갤 수 없는 01 Knapsack 두가지로 분류된다.
Fraction Knapsack의 경우는 가치가 큰 물건부터 선택한 후 나머지 물건을 쪼개는 방식으로 해결하는
그리디 알고리즘을 사용하며,
01 Knapsack의 경우 DP를 이용하여 문제를 해결해야 한다.
각 물건을 넣었을 때, 배낭에 담을 수 있는 무게별 가치의 최대값을 구해가는 방식으로
알고리즘을 진행시켜야한다.
| 물건 | 1 | 2 | 3 | 4 | 
|---|---|---|---|---|
| 무게(w) | 6 | 4 | 3 | 5 | 
| 가치(v) | 13 | 8 | 6 | 12 | 
i = 1
| i \ j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 
|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 13 | 13 | 
| 2 | 0 | |||||||
| 3 | 0 | |||||||
| 4 | 0 | 
i = 2
| i \ j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 
|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 13 | 13 | 
| 2 | 0 | 0 | 0 | 0 | 8 | 8 | 13 | 13 | 
| 3 | 0 | |||||||
| 4 | 0 | 
i번째 물건의 무게(w)가 배낭에 들어갈 수 있는 무게 j보다 클 경우 배낭에 담을 수 없으므로
i-1번 째 물건 단계에서 구했던 최댓값을 그대로 내려받는다.
dp[i][j] = dp[i-1][j]
i = 3
| i \ j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 
|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 13 | 13 | 
| 2 | 0 | 0 | 0 | 0 | 8 | 8 | 13 | 13 | 
| 3 | 0 | 0 | 0 | 6 | 8 | 8 | 13 | 14 | 
| 4 | 0 | 
반대로 w가 j보다 작을 경우 배낭에 담을 수 있으며,
i-1번째 물건 단계에서 구했던 남은 무게의 최대값을 더 담을 수 있게 된다.
즉, dp[i][j] = v(현재 물건의 가치) + dp[i-1][j-w]
다만 전 단계의 최댓값이 더 큰 가치를 가지고 있을 수 있다는 것을 고려해야 한다.
i = 4
| i \ j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 
|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 13 | 13 | 
| 2 | 0 | 0 | 0 | 0 | 8 | 8 | 13 | 13 | 
| 3 | 0 | 0 | 0 | 6 | 8 | 8 | 13 | 14 | 
| 4 | 0 | 0 | 0 | 6 | 8 | 12 | 13 | 14 | 
사이클이 끝나면 위와 같은 표가 완성이 된다.
import sys
input = sys.stdin.readline
arr = []
n, k = map(int, input().split())
dp = [[0 for _ in range(k+1)] for _ in range(n+1)]
for _ in range(n):
  arr.append(list(map(int, input().split())))
for i in range(1, n+1):
  for j in range(1, k+1):
    w = arr[i-1][0]
    v = arr[i-1][1]
    if (j < w):
      dp[i][j] = dp[i-1][j]
    else:
      dp[i][j]=max(v+dp[i-1][j-w], dp[i-1][j])
print(dp[n][k])