www.acmicpc.net/problem/12865

 

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

 

 

 

 

 

 

풀이 .

import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int n = Integer.parseInt(st.nextToken());
        int k = Integer.parseInt(st.nextToken());

        int[] W = new int[n+1];
        int[] V = new int[n+1];
        int[][] dp = new int[n+1][k+1];  // dp[n][k] = 1~N개의 물건으로 무게제한 K 범위에서 가능한 최대 V
        for(int i = 1; i <= n; i++) {
            st = new StringTokenizer(br.readLine());
            int w = Integer.parseInt(st.nextToken());
            int v = Integer.parseInt(st.nextToken());
            W[i] = w;
            V[i] = v;
        }

        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= k; j++) {
                if(W[i] > j) {  // 무게 제한 j로 W[i]이 감당이 안 되는 경우
                    dp[i][j] = dp[i-1][j];
                }else {  // W[i]를 포함해서 새로운 조합을 만들 수 있는 경우 (= j가 W[i] 감당 가능)
                    dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-W[i]] + V[i]);
                }
            }
        }
        System.out.println(dp[n][k]);
    }
}

 

유명한 DP 유형 중 하나인 냅색(Knapsack) 문제라고 한다.

 

입력 값에 대하여 weight, value 두 개의 값이 주어지는 경우를 말한다. 냅색 안에서도 여러 가지 종류로 나눠지는데 이 경우는 0-1 Knapsack이다.

 

입력 값을 더 작은 단위로 나눌 수 없다는 뜻인데 내 수준에서는 그냥 0-1냅색 유형 하나만 있다고 알고 있어도 되지 않을까 싶다.

 

두 개의 입력 값을 어떻게 처리해야 할지, DP배열의 값을 어떻게 정의해야할지 모든 게 낯설고 어색했다.

대표적인 유형이라고 그냥 수업 듣는 느낌으로 조금만 생각해보고 바로 풀이를 확인했다.

 

dp[n][k] = 1~n의 물건을 가지고 무게 제한 k 안에서 채울 수 있는 최대 value 이다.

O(n * k) = 10,000,000 (천 만)으로 충분히 시간 안에 들어올 수 있다.

 

i 반복이 새로 돌 때마다의 의미는 이렇게 표현할 수 있다.

 

i-1번째 물건까지 살펴보았고 배낭의 용량이 j-w[i] 였을 때의 값에, 새롭게 i번째 물건을 넣는 상황

(j-w[i]인 상황에서 넣는 이유는? -> 그래야 i번째 물건을 넣어서 무게가 j가 될 거니까. 무게 j를 채우는 경우를 찾는 건 아니지만 j 범위 안에서 최대 밸류를 찾는 것도 이런식으로 처리할 수 있다)

 

 

 

아.. 너무 어렵다... ㅋㅋ

 

 

 

 

 

'알고리즘 문제 > 백준 온라인 저지' 카테고리의 다른 글

[BOJ] 1874 - 스택 수열 JAVA  (0) 2021.03.07
[BOJ] 1943 - 동전 분배 JAVA  (0) 2021.02.28
[BOJ] 1149 - RGB 거리 JAVA  (0) 2021.02.25
[BOJ] 1662 - 압축 JAVA  (0) 2021.02.25
[BOJ] 14719 - 빗물 JAVA  (0) 2021.02.25

+ Recent posts