

weights 리스트에, 금액은 values 리스트에 저장되어 있다고 가정합시다.bag를 정의합니다.bag[i][j]에는 무게 제한이 j인 배낭에 첫 i개의 물건을 담거나 담지 않을 수 있을 때, 가능한 최대 금액을 저장합니다.bag[4][7]을 찾아야 합니다.
i == 0일 때
i == 0이면 물건이 없으므로, 당연히 배낭에 넣을 수 있는 최대 금액은 0원입니다.j == 0일 때
j == 0이면 배낭의 무게제한이 0이므로, 당연히 아무것도 담을 수 없으니 최대 금액은 0원입니다.
i >= 1 and j >= 1일 때를 채워봅시다.i == 1 (1행)
j열은 배낭의 무게 제한이 j일 때를 뜻한다고 했었죠?bag[1][0] ~ bag[1][5]까진 0으로 채웁니다.bag[1][6] ~ bag[1][7]까진 물건을 담을 수 있으므로, 13으로 채웁니다.
i == 2 (2행)
bag[2][0] ~ bag[2][3]까진 이전 행의 값을 그대로 bag[1][0] ~ bag[1][3]의 값을 복사합니다.bag[2][4]부터는 물건을 넣을 수도 있고, 안 넣을 수도 있습니다.bag[1][4]의 값을 가져옵니다. 물건을 더 안 넣었으니 금액이 바뀌지 않습니다.4 - 4 = 0일 때의 최대 금액에, 현재 물건의 금액 8을 더합니다. 즉 총 금액은 이전 행의 bag[1][0]에 8을 더한 값이 됩니다.bag[2][j] (5 <= j <= 7)도 마찬가지로bag[1][j]와 동일합니다.bag[1][j - 4]에 8을 더한 값이 됩니다.
i == 3 (3행), i == 4 (4행)
values[i - 1], weights[i - 1]입니다. 편의상 curr_v, curr_w로 치환하겠습니다.j가 현재 물건의 무게보다 작은 경우 (j < curr_w)bag[i][j] = bag[i-1][j]. 이전 행 값을 그대로 가져옵니다.j가 현재 물건의 무게 이상인 경우 (j >= curr_v)bag[i - 1][j]. 이전 행 값을 그대로 가져옵니다.bag[i - 1][j - curr_w] + curr_v. 이전 행에서 현재 무게를 뺀 열의 값에다가, 현재 금액을 더합니다.bag[i][j] = max(bag[i - 1][j], bag[i - 1][j - curr_w] + curr_v)의 점화식을 만들 수 있습니다.
# 물품수 N, 최대무게 K
N, K = map(int, input().split())
bag = [[0] * (K + 1) for _ in range(N + 1)]
for i in range(1, N + 1):
# 현재 짐의 무게, 금액
curr_w, curr_v = map(int, input().split())
# 각 행의 열 채우기
for j in range(1, K + 1):
# 배낭의 무게제한이 현재 무게보다 작음
if j < curr_w:
# 넣지 못함 (이전 행의 값)
bag[i][j] = bag[i-1][j]
# 배낭의 무게제한이 현재 무게 이상
else:
# 넣거나 (현재 무게를 비웠을 때 최대 금액) + (현재 금액)
in_result = bag[i-1][j-curr_w] + curr_v
# 넣지 않거나 (이전 행의 값)
out_result = bag[i-1][j]
# 더 큰 값을 선택
bag[i][j] = max(in_result, out_result)
# 모든 물건 + 무게제한 K일 때
print(bag[N][K])