© 2025 anveloper.dev
GitHub·LinkedIn·Contact

목차

  • 문제
  • 입력
  • 출력
  • 예제
  • 풀이
  • 코드
  • 복잡도
풀이 목록으로 돌아가기

BOJ 12865 - 평범한 배낭

2023-01-26
BOJ
골드 V
java
원본 문제 보기
다이나믹 프로그래밍
배낭

문제

BOJ 12865 - 평범한 배낭

이 문제는 아주 평범한 배낭 문제(0/1 Knapsack)이다.

한 달 후면 국가의 부름을 받게 될 정욱이는, 여행을 떠나기로 했다. 여행을 하기 위해 배낭을 하나 구매했는데, 이 배낭에는 최대 K만큼의 무게만 넣을 수 있다. 정욱이가 여행에 필요하다고 생각하는 N개의 물건이 있는데, 각 물건은 무게 W와 가치 V를 가진다. 정욱이는 여행에서 가치의 합이 최대가 되도록 물건을 고르려 한다. 이때 최대 가치를 구하는 프로그램을 작성하시오.

입력

첫 줄에 물품의 수 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

풀이

핵심 아이디어: 0/1 Knapsack 문제의 전형적인 DP 풀이다. dp[i][k]를 i번째 물건까지 고려했을 때 무게 제한 k 이하에서 얻을 수 있는 최대 가치로 정의하고 재귀 + 메모이제이션으로 해결한다.

점화식:

  • 물건 i의 무게가 k보다 크면: dp[i][k] = dp[i-1][k] (i번째 물건을 담을 수 없음)
  • 물건 i의 무게가 k 이하이면: dp[i][k] = max(dp[i-1][k], dp[i-1][k - W[i]] + V[i])

풀이 단계:

  1. 배열 list[i]에 각 물건의 무게와 가치를 저장한다.
  2. dp[i][k]를 null로 초기화하여 아직 계산하지 않은 상태를 표현한다.
  3. recur(N, K)를 호출해 탑-다운 방식으로 결과를 계산한다.
  4. 이미 계산된 값(dp[i][k] != null)이면 메모이제이션된 값을 그대로 반환한다.
  5. i가 0 미만이면 가치 0을 반환한다.

코드

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
 
public class Day353BOJ12865평범한배낭 {
    static int N, K;
    static int[][] list;
    static Integer[][] dp;
 
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
 
        N = Integer.parseInt(st.nextToken());
        K = Integer.parseInt(st.nextToken());
 
        list = new int[N + 1][2];
        dp = new Integer[N + 1][K + 1];
 
        for (int i = 1; i < N + 1; i++) {
            st = new StringTokenizer(br.readLine());
            list[i][0] = Integer.parseInt(st.nextToken());
            list[i][1] = Integer.parseInt(st.nextToken());
        }
        System.out.println(recur(N, K));
        br.close();
    }
 
    private static int recur(int i, int k) {
        if (i < 1)
            return dp[i][k] = 0;
        if (dp[i][k] == null)
            if (list[i][0] > k)
                dp[i][k] = recur(i - 1, k);
            else
                dp[i][k] = Math.max(
                        recur(i - 1, k),
                        recur(i - 1, k - list[i][0]) + list[i][1]);
        return dp[i][k];
    }
}

복잡도

  • 시간: O(NW) — N은 물건 수, W는 배낭 용량. 각 부분 문제 dp[i][k]가 최대 N×W개
  • 공간: O(NW) — DP 테이블 크기