백준 12865 - 평범한 배낭 (Python3)
코드
n, k = map(int, input().split())
# 가지고갈 물건의 무게와 가치를 담을 리스트
# 처음 0,0 값을 넣어서 인덱스를 편하게 관리할 수 있음
ob = [[0, 0]]
# DP 테이블
# k+1만큼 0을 넣고, n+1만큼 행을 갖게 만듬
# 마찬가지로 인덱스를 편하게 관리할 수 있음
pack = [[0 for _ in range(k+1)] for _ in range(n+1)]
for _ in range(n):
# w, v 입력받음
ob.append(list(map(int, input().split())))
# 1~n, 1~k 만큼 반복
for i in range(1, n+1):
# j : 배낭에 담을 수 있는 최대 무게
for j in range(1, k+1):
# 무게와 가치를 뽑아냄
w = ob[i][0]
v = ob[i][1]
# i번째 물건의 무게보다 작다 => 배낭이 담을 수 있는 무게를 초과했다
# 당연히 못 넣으므로 그전 DP 테이블의 값을 그대로 가져옴
if j < w:
# 바로 전까지의 누적 v값을 그대로 가져옴
pack[i][j] = pack[i-1][j]
# 크거나 같다 => 배낭에 추가로 더 넣을 수 있다
else:
# pack[i-1][j-w] + v의 의미
# i번째 물건을 넣지 않는 경우, 배낭에 담을 수 있는 최대 무게는
# i번째 물건의 무게를 뺀 나머지가 되므로 => j-w가 된다
# pack[i-1][j-w]는 i번째 물건을 넣기 전까지의 최대 효용 가치가 되고
# 여기에 v (i번째 물건의 가치)를 더해주면 원하는 값을 구할 수 있다
# 위의 주석 과정을 넣은 경우와 넣지 않은 경우 둘 중 더 큰 값을 DP 테이블에 업데이트 해줌
pack[i][j] = max(pack[i-1][j], pack[i-1][j-w] + v)
print(pack[n][k])
문제 해설
DP 문제에서 매우 유명한 냅색(배낭) 문제. (냅색 문제 나무위키 참고)
이 문제를 접하기 전까지 이 유형의 문제가 유명하다는 것 조차 알지 못했다 ㅠㅠ
풀이 순서
- DP 테이블을 2차원 리스트로 생성하여 보유한 물건들을 순서대로 최대 허용 무게만큼 하나씩 넣어주면서 최대 효용 가치를 계산한다
- 무게가 초과되면 이전 아이템을 빼거나 기존 그대로 가지는 방법 중 하나를 선택하여 DP 테이블을 계속해서 업데이트 해준다
위 두 과정을 반복하여 거쳐 마지막 DP 테이블까지 모두 업데이트 시키면 최종적으로 가치합의 최댓값을 구할 수 있다.
댓글남기기