말감로그

[백준] 12865 평범한 배낭 (파이썬) 본문

백준

[백준] 12865 평범한 배낭 (파이썬)

habbn 2024. 1. 31. 15:56
728x90

 

 

12865번: 평범한 배낭

첫 줄에 물품의 수 N(1 ≤ N ≤ 100)과 준서가 버틸 수 있는 무게 K(1 ≤ K ≤ 100,000)가 주어진다. 두 번째 줄부터 N개의 줄에 거쳐 각 물건의 무게 W(1 ≤ W ≤ 100,000)와 해당 물건의 가치 V(0 ≤ V ≤ 1,000)

www.acmicpc.net

 

문제

이 문제는 아주 평범한 배낭에 관한 문제이다.

한 달 후면 국가의 부름을 받게 되는 준서는 여행을 가려고 한다. 세상과의 단절을 슬퍼하며 최대한 즐기기 위한 여행이기 때문에, 가지고 다닐 배낭 또한 최대한 가치 있게 싸려고 한다.

준서가 여행에 필요하다고 생각하는 N개의 물건이 있다. 각 물건은 무게 W와 가치 V를 가지는데, 해당 물건을 배낭에 넣어서 가면 준서가 V만큼 즐길 수 있다. 아직 행군을 해본 적이 없는 준서는 최대 K만큼의 무게만을 넣을 수 있는 배낭만 들고 다닐 수 있다. 준서가 최대한 즐거운 여행을 하기 위해 배낭에 넣을 수 있는 물건들의 가치의 최댓값을 알려주자.

입력

첫 줄에 물품의 수 N(1 ≤ N ≤ 100)과 준서가 버틸 수 있는 무게 K(1 ≤ K ≤ 100,000)가 주어진다. 두 번째 줄부터 N개의 줄에 거쳐 각 물건의 무게 W(1 ≤ W ≤ 100,000)와 해당 물건의 가치 V(0 ≤ V ≤ 1,000)가 주어진다.

입력으로 주어지는 모든 수는 정수이다.

출력

한 줄에 배낭에 넣을 수 있는 물건들의 가치합의 최댓값을 출력한다.

예제 입력 1 

4 7
6 13
4 8
3 6
5 12

예제 출력 1 

14

 


주제 - DP (Knapsack Problem)

 

유명한 Knapsack Problem 배낭 문제는 담을 수 있는 최대 무게가 정해진 배낭이 있고 각각의 무게와 가치가 주어진 물건들이 주어졌을 때, 배낭에 담은 물건들의 가치가 최대가 되도록 하게 물건을 고르는 방법을 찾는 문제이다.

 

풀이과정

1. 1~k까지의 행(배낭 무게)과 n개의 열(물건)만큼의 배열을 만들어준다,
2. 현재 물건의 무게와 가치를 담을 리스트를 만들어준다.
3. 현재 물건의 무게가 현재 dp 무게보다 작으면 작아서 물건을 담지 못하므로  [이전물건][같은 무게]를 입력해 준다.
 -> dp[i-1][j]
4. 현재 물건을 넣을 수 있다면 이전 물건과 현재 물건을 넣었을 때의 value 값을 비교해서 더 큰걸 저장한다.
 -> max(dp[i-1][j] , dp[i-1][j-w] + v)

 

 

dp 표는 이렇게 채워질 것이다.

 

 

행에는 배낭의 무게, 열에는 물건이 들어가고 v는 물건의 가치이다

 

이 표를 보면서 무게가 4인 물건을 넣으려고 할 때 현재 물건의 무게가 현재 dp무게보다 작을 때까지는 물건을 담지 못하기 때문에 dp[i-1][j] 를 입력해 준다.(이전 물건의 값을 그대로 가져온다. ) -> 0을 입력

 

dp[i][j] = dp[i-1][j]

 

그러다 넣을 수 있는 무게가 되었을 때(4 이상) 이전 물건과 현재 물건을 넣었을 때의 value 값을 비교해 더 큰걸 저장한다

 

dp[i][j] = max(dp[i-1][j], dp[i-1][j-w] +v) 

 

(i와 j가 1부터 시작한다고 했을 때) 

dp[1][4] = max(dp[0][4] + dp[0][4-4] +8) -> max(0,8) -> 현재 물건의 value 8이 더 크기 때문에 8을 저장한다.

 

만약 j가 6이 되었을 때는 어떻게 되느냐 점화식에 대입해 보면

dp[1][6] = max(dp[0][6] + dp[0][6-4] + 8) -> max(13,8) -> 이전 물건의 value 13이 더 크기 때문에 13을 저장한다.

 

이런 식으로 계속해서 이전물건과 현재 물건을 넣었을 때의 value를 비교해서 더 큰걸 저장하게 되면 배낭에 담은 물건들의 가치가 최대가 되도록 만들 수 있다.

 

너무 주저리주저리 설명한 거 같지만 이렇게 하나씩 대입해 보면서 풀면 이해가 더 빠를 것이다.


 

완성코드

import sys
input = sys.stdin.readline

n, k = map(int,input().split())

dp = [[0] *(k+1) for _ in range(n+1)]

bag = [[0,0]]

for i in range(n):
    bag.append(list(map(int,input().split())))
    
for i in range(1,n+1):        
    w = bag[i][0]
    v = bag[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], dp[i-1][j-w] +v)
        
print(dp[n][k])

 

 

참고 https://claude-u.tistory.com/208
728x90