[알고리즘][X] 보석 도둑
2024. 4. 16. 12:24ㆍ알고리즘 풀이/Java
https://www.acmicpc.net/problem/1202
1202번: 보석 도둑
첫째 줄에 N과 K가 주어진다. (1 ≤ N, K ≤ 300,000) 다음 N개 줄에는 각 보석의 정보 Mi와 Vi가 주어진다. (0 ≤ Mi, Vi ≤ 1,000,000) 다음 K개 줄에는 가방에 담을 수 있는 최대 무게 Ci가 주어진다. (1 ≤ Ci
www.acmicpc.net
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.StringTokenizer;
public class Main {
static class Jewel {
int M; // 무게
int V; // 가격
public Jewel() {
super();
}
public Jewel(int m, int v) {
super();
M = m;
V = v;
}
}
public static void main(String[] args) throws Exception {
// 보석 N, 무게 M, 가격 V, 가방 수 K 가방 최대 무게 C
// 차원: 보석, 무게, 가방 3차원
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken()), K = Integer.parseInt(st.nextToken());
Jewel[] jewels =new Jewel[N];
for (int i = 0; i < N; i++) {
st = new StringTokenizer(br.readLine());
jewels[i] = new Jewel();
jewels[i].M = Integer.parseInt(st.nextToken());
jewels[i].V = Integer.parseInt(st.nextToken());
}
int[] C = new int[K];
for (int i = 0; i < K; i++) {
st = new StringTokenizer(br.readLine());
C[i] = Integer.parseInt(st.nextToken());
}
// 보석을 무게 오름차순으로 정렬
// 가방을 무게 오름차순으로 정렬
Arrays.sort(jewels, new Comparator<Jewel>() {
@Override
public int compare(Jewel o1, Jewel o2) {
return o1.M - o2.M;
}
});
Arrays.sort(C);
// 가방과 보석에 각각 포인터를 두고 현재 가방보다 낮은 무게를 가지는 보석을 넣어둠
// 이때 보석을 넣어두는 장소는 힙으로 가치 내림차순으로 정렬
PriorityQueue<Jewel> pq = new PriorityQueue<>(new Comparator<Jewel>() {
@Override
public int compare(Jewel o1, Jewel o2) {
return o2.V - o1.V;
}
});
long result = 0;
int bagIdx = 0;
int jewelIdx = 0;
// 가방을 모두 보거나 보석을 모두 보면 일단 종료
while (bagIdx < K && jewelIdx < N) {
if (C[bagIdx] >= jewels[jewelIdx].M) {
pq.add(jewels[jewelIdx]);
jewelIdx++;
continue;
}
// 보석이 있다면 최대 가치 더해줌
if (!pq.isEmpty()) {
Jewel jewel = pq.poll();
result += jewel.V;
}
bagIdx++;
}
// 가방이 남아있고 보석도 남아있다면 하나가 남지 않을때까지 계속
while (bagIdx < K && !pq.isEmpty()) {
Jewel jewel = pq.poll();
result += jewel.V;
bagIdx++;
}
System.out.println(result);
}
}
나의 풀이
- 보석 하나의 최대 크기가 1억이고 최대 개수가 300,000 이기 때문에 long을 써야 한다. 이것 때문에 틀렸었다.
- dp로 풀려고 하면 시간초과가 난다.
- 따라서 그리디를 활용해야 한다.
- 먼저 무게별로 가방과 보석을 각각 정렬해준다.
- 그리고 가방과 보석에 각각의 현재 위치를 가리키는 포인터를 둔다.
- 현재 가방보다 낮은 무게를 가진 보석을 모두 힙에 넣어준다. 이때 힙은 보석의 가치를 내림차순으로 정렬하는 맥스힙이다.
- 현재 가방보다 낮은 무게를 가진 보석이 없다면 힙에서 최대 가치를 지닌 보석을 빼준다.
- 힙에 있는 보석은 그 다음번째에 있는 가방이 모두 선택할 수 있기 때문에 논리가 성립한다.
- 상대적으로 낮은 최대 무게 가방이 선택의 폭이 좁기 때문에 먼저 선택권을 줘야만 한다. 높은 최대 무게 가방은 낮은 최대 무게 가방이 선택할 수 있는 것 중 어떤 것이라도 선택할 수 있기 때문이다.
- 반대는 성립하지 않는다.
'알고리즘 풀이 > Java' 카테고리의 다른 글
[알고리즘][X] 통나무 옮기기 (0) | 2024.04.22 |
---|---|
[알고리즘] 히스토그램 (0) | 2024.04.18 |
[알고리즘][X] 소수의 연속합 (0) | 2024.04.15 |
[알고리즘][X] 계단 수 (0) | 2024.04.14 |
[알고리즘][X] 술래 잡기 (0) | 2024.04.09 |