읽기 전
- 불필요한 코드나 잘못 작성된 내용에 대한 지적은 언제나 환영합니다.
- 개인적으로 배운 점을 정리한 글입니다.
문제 링크
문제 풀이
0-1 냅색(0-1 Knapsack) 문제라고도 부르며 대표적인 DP문제로 소개되곤 한다. 다만 그 풀이는 하위 문제 분할이 잘 생각나지 않을 수 있으므로 한 번은 짚고 넘어 가야겠다.
가방에 들어가는 짐의 개수와 무게가 주어진 제약조건을 기준으로 1씩 분할된다고 해보자.
각 짐에 대해 탐색을 진행하되 0부터 W까지 탐색한다. 탐색에 쓰이는 짐의 무게가 탐색 중인 허용치보다 작거나 같을 때 이전 짐에서 탐색한 결과와 비교하여 갱신하면 되겠다.
시간제한이 빡빡한 편이여서 풀이 자체는 정답이지만 주소 할당이나 리스트 생성에서 비효율이 발생하면 여지없이 TLE를 출력한다.
python 코드
import sys
input = sys.stdin.readline
N, K = map(int, input().split())
cargo = []
for _ in range(N):
cargo.append(list(map(int, input().split())))
dp = [[0] * (K + 1) for _ in range(N + 1)]
for i in range(1, N + 1): # 각 짐에 대해
for j in range(1, K + 1): # 각 저장용량에 대해
if cargo[i - 1][0] <= j: # 만약 짐이 용량 이하라면
dp[i][j] = max(
dp[i - 1][j], # 이전 짐의 동일 허용치 값과
dp[i - 1][c - cargo[i - 1][0]] + cargo[i - 1][1]
# 이전 짐의 허용치-현재 짐 무게의 값 + 현재 짐 가치와 비교
)
else:
dp[i][j] = dp[i - 1][j] # 용량보다 크면 이전과 값 동일
print(dp[N][K])
여기서 탐색 짐의 용량이 허용치보다 클 경우 굳이 탐색을 할 필요가 없다. 그리고 dp 배열도 굳이 2차원이 아니라 탐색 횟수는 별 차이 없겠지만 용량을 기준으로 1차원 배열로 만들 수 있을 듯 하다.
python 코드
import sys
input = sys.stdin.readline
N, K = map(int, input().split())
cargo = []
for _ in range(N):
cargo.append(list(map(int, input().split())))
dp = [0 for _ in range(K + 1)] # 각 무게에 대해
for w, k in cargo:
for c in range(K, w - 1, -1): # 마지막 용량부터 탐색 짐 무게까지
dp[c] = max(dp[c], dp[c - w] + k) # 현재값, 용량-현재무게 + 가치
print(dp[K])
'Algorithms > Baekjoon' 카테고리의 다른 글
BOJ #11054 가장 긴 바이토닉 부분 수열 (0) | 2021.07.28 |
---|---|
BOJ #11444 피보나치 수 6 (0) | 2021.07.28 |
BOJ #11053 가장 긴 증가하는 부분 수열 (0) | 2021.07.26 |
BOJ #10844 쉬운 계단 수 (0) | 2021.07.26 |
BOJ #2156 포도주 시식 (0) | 2021.07.26 |