
문제
이 문제는 아주 평범한 배낭에 관한 문제이다.
한 달 후면 국가의 부름을 받게 되는 준서는 여행을 가려고 한다. 세상과의 단절을 슬퍼하며 최대한 즐기기 위한 여행이기 때문에, 가지고 다닐 배낭 또한 최대한 가치 있게 싸려고 한다.
준서가 여행에 필요하다고 생각하는 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)가 주어진다.
입력으로 주어지는 모든 수는 정수이다.
출력
한 줄에 배낭에 넣을 수 있는 물건들의 가치합의 최댓값을 출력한다.
아이디어
최대 물건을 4개까지 챙겨간다고 했으니, 물건을 1개만 가져갈 수도 있을 것이라고 생각했다.
그러면, 가방 무게를 고정시키고, 물건을 넣었다가 빼면서 최대한의 가치를 챙길 수 있을 것같다.
행은 최대로 챙겨가는 갯수이고, 코드로 작성할 때, 편하게 하기 위해 0부터 시작해서 4까지 총 5칸을 사용한다.
열은 행만큼 물건을 챙겨갈 때, 소비하는 무게를 의미한다.
가방의 무게 | |||||||||
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ||
N개의 아이템 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 6 | 6 | 6 | 6 | 6 | |
2 | 0 | 0 | 0 | 6 | 8 | 8 | 8 | 14 | |
3 | 0 | 0 | 0 | 6 | 8 | 12 | 12 | 14 | |
4 | 0 | 0 | 0 | 6 | 8 | 12 | 13 | 14 |
(넣을 아이템들이 오름차순으로 정렬되어 있다고 가정한다.)
1번 아이템을 가지고 1개의 아이템을 고르게 된다면 최대로 가져갈 수 있는 무게에 따라 가질 수 있는 가치를 알 수 있다.
만약, 2개의 아이템을 뽑는다면 이전의 가치에 현재 넣으려고 하는 물건의 무게만큼 열에서 빼준 인덱스의 가치에 현재 넣으려고 하는 물건의 가치를 더해준 값중 최대 값을 추출한다.
dp[i][j]는 i번째 물건까지 고려했을 때, 배낭의 무게가 j일 때의 최대 가치를 의미한다.
i번째 물건을 넣을 수 없는 경우, dp[i][j] = dp[i-1][j]이다.
i번째 물건을 넣을 수 있는 경우, dp[i][j] = dp[i-1][j]와 dp[i-1][j-weight] + value 중 큰 값이다.
dp[i-1][j]는 i번째 물건을 넣지 않았을 때의 가치이다.
dp[i-1][j-weight] + value는 i번째 물건을 넣었을 때의 가치이다.
dp[i][j]는 i번째 물건까지 고려했을 때, 배낭의 무게가 j일 때의 최대 가치를 의미한다.
소스코드
// 백준 12865번 평법한 배낭
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.util.stream.Stream;
class Main{
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int[] nums = Stream.of(br.readLine().split(" ")).mapToInt(Integer::parseInt).toArray();
int N = nums[0];
int K = nums[1];
int[][] items = new int[N][2];
for (int i = 0; i < N; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());;
items[i][0] = Integer.parseInt(st.nextToken());
items[i][1] = Integer.parseInt(st.nextToken());
}
int[][] dp = new int[N+1][K+1];
for (int i = 1; i < N+1; i++) {
for (int j = 1; j < K+1; j++) {
int weight = items[i-1][0];
int value = items[i-1][1];
if(j < weight){
dp[i][j] = dp[i-1][j];
}else{
dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-weight] + value);
}
}
}
System.out.println(dp[N][K]);
}
}
결과

후기
이전 포스팅에서는 DP에 대한 포스팅을 작성했었는데, DP를 학습하고 바로 백준 문제를 풀어보니까 생각보다 쉽게 풀린 것같다.
하지만, 조금만 쉬어도 빠지는 코테 근육때문에 지속적으로 공부를 하면서 잊지않도록 해야할 것같다.
냅색 알고리즘은 다른 코테 시험에서도 자주 나오게 되는 문제인 것 같아서 더욱 중요한 것같다.
'코딩 테스트' 카테고리의 다른 글
[백준 골드3] 2830번 행성 X3 / Java (0) | 2024.04.23 |
---|---|
[프로그래머스 level3] 디스크 컨트롤러 / Java (0) | 2024.04.21 |
[백준 실버5] 24174 알고리즘 수업 - 힙 정렬2 / Java (0) | 2024.04.21 |
[백준 실버4] 요세푸스 문제 / Java (1) | 2024.04.19 |
[프로그래머스 level2] 프로세스 / Java (0) | 2024.04.19 |

문제
이 문제는 아주 평범한 배낭에 관한 문제이다.
한 달 후면 국가의 부름을 받게 되는 준서는 여행을 가려고 한다. 세상과의 단절을 슬퍼하며 최대한 즐기기 위한 여행이기 때문에, 가지고 다닐 배낭 또한 최대한 가치 있게 싸려고 한다.
준서가 여행에 필요하다고 생각하는 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)가 주어진다.
입력으로 주어지는 모든 수는 정수이다.
출력
한 줄에 배낭에 넣을 수 있는 물건들의 가치합의 최댓값을 출력한다.
아이디어
최대 물건을 4개까지 챙겨간다고 했으니, 물건을 1개만 가져갈 수도 있을 것이라고 생각했다.
그러면, 가방 무게를 고정시키고, 물건을 넣었다가 빼면서 최대한의 가치를 챙길 수 있을 것같다.
행은 최대로 챙겨가는 갯수이고, 코드로 작성할 때, 편하게 하기 위해 0부터 시작해서 4까지 총 5칸을 사용한다.
열은 행만큼 물건을 챙겨갈 때, 소비하는 무게를 의미한다.
가방의 무게 | |||||||||
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ||
N개의 아이템 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 6 | 6 | 6 | 6 | 6 | |
2 | 0 | 0 | 0 | 6 | 8 | 8 | 8 | 14 | |
3 | 0 | 0 | 0 | 6 | 8 | 12 | 12 | 14 | |
4 | 0 | 0 | 0 | 6 | 8 | 12 | 13 | 14 |
(넣을 아이템들이 오름차순으로 정렬되어 있다고 가정한다.)
1번 아이템을 가지고 1개의 아이템을 고르게 된다면 최대로 가져갈 수 있는 무게에 따라 가질 수 있는 가치를 알 수 있다.
만약, 2개의 아이템을 뽑는다면 이전의 가치에 현재 넣으려고 하는 물건의 무게만큼 열에서 빼준 인덱스의 가치에 현재 넣으려고 하는 물건의 가치를 더해준 값중 최대 값을 추출한다.
dp[i][j]는 i번째 물건까지 고려했을 때, 배낭의 무게가 j일 때의 최대 가치를 의미한다.
i번째 물건을 넣을 수 없는 경우, dp[i][j] = dp[i-1][j]이다.
i번째 물건을 넣을 수 있는 경우, dp[i][j] = dp[i-1][j]와 dp[i-1][j-weight] + value 중 큰 값이다.
dp[i-1][j]는 i번째 물건을 넣지 않았을 때의 가치이다.
dp[i-1][j-weight] + value는 i번째 물건을 넣었을 때의 가치이다.
dp[i][j]는 i번째 물건까지 고려했을 때, 배낭의 무게가 j일 때의 최대 가치를 의미한다.
소스코드
// 백준 12865번 평법한 배낭
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.util.stream.Stream;
class Main{
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int[] nums = Stream.of(br.readLine().split(" ")).mapToInt(Integer::parseInt).toArray();
int N = nums[0];
int K = nums[1];
int[][] items = new int[N][2];
for (int i = 0; i < N; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());;
items[i][0] = Integer.parseInt(st.nextToken());
items[i][1] = Integer.parseInt(st.nextToken());
}
int[][] dp = new int[N+1][K+1];
for (int i = 1; i < N+1; i++) {
for (int j = 1; j < K+1; j++) {
int weight = items[i-1][0];
int value = items[i-1][1];
if(j < weight){
dp[i][j] = dp[i-1][j];
}else{
dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-weight] + value);
}
}
}
System.out.println(dp[N][K]);
}
}
결과

후기
이전 포스팅에서는 DP에 대한 포스팅을 작성했었는데, DP를 학습하고 바로 백준 문제를 풀어보니까 생각보다 쉽게 풀린 것같다.
하지만, 조금만 쉬어도 빠지는 코테 근육때문에 지속적으로 공부를 하면서 잊지않도록 해야할 것같다.
냅색 알고리즘은 다른 코테 시험에서도 자주 나오게 되는 문제인 것 같아서 더욱 중요한 것같다.
'코딩 테스트' 카테고리의 다른 글
[백준 골드3] 2830번 행성 X3 / Java (0) | 2024.04.23 |
---|---|
[프로그래머스 level3] 디스크 컨트롤러 / Java (0) | 2024.04.21 |
[백준 실버5] 24174 알고리즘 수업 - 힙 정렬2 / Java (0) | 2024.04.21 |
[백준 실버4] 요세푸스 문제 / Java (1) | 2024.04.19 |
[프로그래머스 level2] 프로세스 / Java (0) | 2024.04.19 |