문제 분류
다이나믹 프로그래밍, 배낭 문제
문제 난이도
골드 5
문제
이 문제는 아주 평범한 배낭에 관한 문제이다.
한 달 후면 국가의 부름을 받게 되는 준서는 여행을 가려고 한다. 세상과의 단절을 슬퍼하며 최대한 즐기기 위한 여행이기 때문에, 가지고 다닐 배낭 또한 최대한 가치 있게 싸려고 한다.
준서가 여행에 필요하다고 생각하는 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)가 주어진다.
입력으로 주어지는 모든 수는 정수이다.
출력
한 줄에 배낭에 넣을 수 있는 물건들의 가치합의 최댓값을 출력한다.
예시
문제풀이
어려운 DP문제이다. 배낭 문제는 대표적인 DP문제라고 잘 알려져 있어서 DP임을 깨달았습니다..!!
DP 배열 설정
DP 문제를 풀 때 가장 어렵지만 중요한 것은 DP 배열을 어떻게 설정할 것인가 입니다.
이 문제에서는 dp[아이템 번호][무게] 형태로 2차원 배열을 설정했습니다. 즉, dp[i][w]는 i번째 아이템까지 고려했을 때, 배낭의 무게가 w일 때 얻을 수 있는 최대 가치를 말합니다.
표 그리기
무게가 6인 아이템을 추가했을 때 DP는 아래와 같습니다.
무게가 4인 아이템을 추가했을 때 DP는 아래와 같습니다.
여기까지는 쉽다. 이제부터 문제이다 ㅎㅎ
무게가 3인 아이템을 생각해볼 때, 문제가 복잡해집니다.
- 무게가 3, 4, 5, 6일 때 : 기존 값으로 값을 갱신합니다.
- 무게가 7일 때 : 새로 추가된 아이템(무게가 3인 아이템)과 기존 아이템(무게가 4인 아이템)의 가치를 비교해야 합니다.
무게가 7이 되는 순간 무게가 3인 아이템과 무게가 4인 아이템의 가치의 합과 기존의 무게값과 비교를 해야 한다.
즉 해당 예제에서, 원래 무게가 7인 가치의 값은 13이었지만 무게가 3인 아이템의 가치(6)와 무게가 4인 아이템의 가치(8)의 합은 14이므로 14로 값을 갱신해야 한다.
무게가 5인 아이템까지 채우면 전체 표는 아래와 같이 그려집니다.
🤔 조금 더 깊게 생각해보자
int weight = items[i][0];
int value = items[i][1];
if (j - weight >= 0) {
dp[i][j] = Math.max(dp[i][j], dp[i-1][j-weight] + value);
}
값을 갱신할 때 위와 같은 코드가 진행되는데, 하나씩 뜯어보자.
if (j - weight >= 0) : 현재 무게(j)에서 새로운 아이템의 무게(weight)를 뺀 값이 0 이상인지 확인합니다. 현재 배낭에 새로운 아이템을 넣을 수 있는지 판단하는 과정입니다.
Math.max(dp[i][j], dp[i-1][j-weight] + value); : 여기서는 두 가지 경우를 비교하여 최대값으로 갱신합니다.
- 아이템을 넣지 않는 경우(dp[i][j])
- 아이템을 넣는 경우(dp[i-1][j-weight] + value)
🎯 결론 : 현재 배낭 무게에서 i번째 아이템을 포함한 경우와 포함하지 않은 경우 중 어떤 것이 더 큰 가치를 얻는지 판단해야 한다!
전체 코드
import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String[] s = bf.readLine().split(" ");
int N = Integer.parseInt(s[0]); // 물품의 수
int K = Integer.parseInt(s[1]); // 버틸 수 있는 무게
int[][] items = new int[N+1][2]; // items[무게][가치]
int[][] dp = new int[N+1][K+1]; // dp[아이템][무게]
for (int i = 1; i <= N; i++) {
StringTokenizer st = new StringTokenizer(bf.readLine());
items[i][0] = Integer.parseInt(st.nextToken());
items[i][1] = Integer.parseInt(st.nextToken());
}
for (int i = 1; i < N+1; i++) {
int weight = items[i][0];
int value = items[i][1];
for (int j = 1; j <= K; j++) {
dp[i][j] = dp[i-1][j];
if (j - weight >= 0) {
dp[i][j] = Math.max(dp[i][j], dp[i-1][j-weight] + value);
}
}
}
int answer = Integer.MIN_VALUE;
for (int i = 0; i < N+1; i++) {
answer = Arrays.stream(dp[i]).max().getAsInt();
}
bw.write(answer + "\n");
bw.flush();
bw.close();
}
}'알고리즘 > BAEKJOON' 카테고리의 다른 글
| [백준] 16678 : 모독 (0) | 2025.01.14 |
|---|---|
| [백준] 13164 : 행복 유치원 (0) | 2025.01.13 |
| [백준] 2579 : 계단 오르기 (0) | 2025.01.03 |
| [백준] 1374 : 강의실 (1) | 2024.12.25 |
| [백준] 1461 : 도서관 (0) | 2024.12.24 |
