Algorithm/Dynamic Programming
[DP] 백준 12865번 “평범한 배낭” Python 풀이
운호(Noah)
2024. 3. 15. 13:40
들어가기 앞서,
- 배낭 문제(Knapsack Problem)는 제한된 공간에 가치가 높은 물건들을 최대한 많이 넣는 문제입니다.
- 이 문제는 물건을 나눌 수 있냐 없냐에 따라 두 가지 유형으로 나뉩니다.
- 분할 가능한 배낭 문제(Fractional Knapsack Problem)
- 물건을 일부분으로 나눌 수 있는 경우 (예: 설탕 500g 중 300g만 넣기)
- 그리디 알고리즘으로 해결 가능
- 0-1 배낭 문제(0-1 Knapsack Problem)
- 물건을 나눌 수 없고, 전부 넣거나 전혀 넣지 않아야 하는 경우
- 동적 프로그래밍(Dynamic Programming)으로 해결 가능
- 분할 가능한 배낭 문제(Fractional Knapsack Problem)
- 해당 문제는 0-1 배낭 문제(0-1 Knapsack Problem)에 해당됩니다.
설명
- 문제 설정
- 물건 개수: N = 4
- 배낭 용량: K = 7
- 물건 정보: (무게, 가치) = (6, 13), (4, 8), (3, 6), (5, 12)
- 동적 프로그래밍 테이블 d[n][k] 정의
- d[n][k]
- n번째 물건까지 고려했을 때, 배낭 용량 k에서 얻을 수 있는 최대 가치
- d[n][k]
- 재귀 관계식
- 현재 물건 i, 현재 물건의 무게 weight, 현재 물건의 가치 value, 담으려는 배낭의 용량 j 일 때
- 경우 1) 현재 물건을 배낭에 담을 수 없는 경우 (weight > j)
- d[i][j] = d[i-1][j]
- 이전 물건을 담았을 때까지의 최대 가치
- d[i][j] = d[i-1][j]
- 경우 2) 현재 물건을 배낭에 담을 수 있는 경우 (weight ≤ j)
- d[i][j] = max( d[i-1][j-weight] + value , d[i-1][j] )
- d[i-1][j-weight] + value : 현재 물건의 무게만큼 배낭에서 뺀 뒤, 현재 물건을 담았을 때의 최대 가치
- d[i-1][j] : 현재 물건을 담지 않았을 때의 최대 가치
- d[i][j] = max( d[i-1][j-weight] + value , d[i-1][j] )
- 최종 코드
- 모든 값이 채워진 2차원 DP 테이블의 d[N][K] 값
진행 순서
첫 번째 물건(6, 13) 고려
두 번째 물건(4, 8) 고려
세 번째 물건(3, 6) 고려
네 번째 물건(5, 12) 고려
예제 코드
import sys
# 물건 개수, 배낭의 최대 용량
n, k = map(int, sys.stdin.readline().split())
# DP 테이블
dp = [[0] * (k+1) for _ in range(n+1)]
# 다루고자하는 물건(무게, 가치) 목록
items = [[0, 0]]
for _ in range(n):
w, v = map(int, sys.stdin.readline().split())
items.append([w, v])
for i in range(1, n+1):
# 현재 물건의 무게와 가치
w = items[i][0]
v = items[i][1]
for j in range(1, k+1):
# 현재 물건을 배낭에 담을 수 없는 경우
if (w > j):
dp[i][j] = dp[i-1][j]
# 현재 물건을 배낭에 담을 수 있는 경우
else:
dp[i][j] = max(dp[i-1][j-w] + v, dp[i-1][j])
print(dp[n][k])