문제
세계적인 도둑 상덕이는 보석점을 털기로 결심했다.
상덕이가 털 보석점에는 보석이 총 N개 있다. 각 보석은 무게 Mi와 가격 Vi를 가지고 있다. 상덕이는 가방을 K개 가지고 있고, 각 가방에 담을 수 있는 최대 무게는 Ci이다. 가방에는 최대 한 개의 보석만 넣을 수 있다.
상덕이가 훔칠 수 있는 보석의 최대 가격을 구하는 프로그램을 작성하시오.
입력
첫째 줄에 N과 K가 주어진다. (1 ≤ N, K ≤ 300,000)
다음 N개 줄에는 각 보석의 정보 Mi와 Vi가 주어진다. (0 ≤ Mi, Vi ≤ 1,000,000)
다음 K개 줄에는 가방에 담을 수 있는 최대 무게 Ci가 주어진다. (1 ≤ Ci ≤ 100,000,000)
모든 숫자는 양의 정수이다.
출력
첫째 줄에 상덕이가 훔칠 수 있는 보석 가격의 합의 최댓값을 출력한다.
예제 입력 1 복사
2 1
5 10
100 100
11
예제 출력 1 복사
10
예제 입력 2 복사
3 2
1 65
5 23
2 99
10
2
예제 출력 2 복사
164
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
문제 풀이
해당 문제는 간단한 그리디 문제로 보이지만 일차원적으로 그리디로만 푼다면 쉽게 풀 수 있지만, 시간복잡도에서 통과하기가 쉽지 않은 문제였다.
처음에 풀 때, 우선 순위 큐를 사용하여 해당 무게에서 최대로 챙길 수 있는 무게를 구했지만 시간 초과가 떴다.
이 후 추가적으로 tempPq를 생성하여 최적의 보석을 제거하고 다시 pq에 넣어가며 두개의 우선 순위 큐를 사용해보았지만 이 방법으로도 시간 초과가 떴다.
이 문제에서 효율적으로 그리디를 진행하기 위해서는 리스트와 우선순위 큐를 같이 사용하는 것이다.
문제 풀이 과정은 아래와 같다.
- 보석을 arraylist로 입력받은 후 무게 순서대로 오름차순 정렬한다.
- 가방에 담을 수 있는 최대 무게를 입력 받은 후 오름차순 정렬한다.
- 가격 순서대로 내림차순 정렬을 하는 우선순위 큐를 생성한다.
- 현재 가방이 담을 수 있는 최대 무게보다 작거나 같은 무게를 가진 보석을 우선순위 큐에 담아준다.
- 우선순위 큐의 제일 첫 번째 값(가장 가격이 비싼 보석)을 꺼내어 더해준다.
- 4 ~ 5를 반복해주면 된다.
처음에 풀 때는 Class에 compareTo 메서드를 설정하여 하나의 기준으로 정렬을 하였지만 위 과정에서는 리스트와 우선 순위 큐의 조건을 다르게 설정하여서 풀었다.
- 리스트 : 무게 오름차순
- 우선 순위 큐 : 가격 내림차순
위와 같이 적용을 하여 현재 가방에서 가지고 갈 수 있는 보석 중 peek의 가장 가격이 높은 보석을 챙기는 방식으로 구현하였다.
풀이 코드
import java.util.*;
import java.io.*;
public class Main {
public static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
public static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
public static StringTokenizer st;
public static int INF = 100_000_000;
public static int[] dx = {0,1,0,-1};
public static int[] dy = {-1,0,1,0};
public static class Crystal{
int mass;
int value;
public Crystal() {}
public Crystal(int mass, int value) {
this.mass = mass;
this.value = value;
}
@Override
public String toString() {
return "Crystal [mass=" + mass + ", value=" + value + "]";
}
}
public static void main(String[] args) throws IOException{
st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
int M = Integer.parseInt(st.nextToken());
List<Crystal> list = new ArrayList<>();
int[] backpack = new int[M];
for(int i = 0 ; i < N; i++) {
st = new StringTokenizer(br.readLine());
int m = Integer.parseInt(st.nextToken());
int v = Integer.parseInt(st.nextToken());
list.add(new Crystal(m,v));
}
Collections.sort(list,(a,b) -> a.mass - b.mass);
for(int i = 0; i < M; i++) {
int size = Integer.parseInt(br.readLine());
backpack[i] = size;
}
Arrays.sort(backpack);
int listIdx = 0;
long answer = 0;
PriorityQueue<Crystal> pq = new PriorityQueue<>((a,b) -> b.value - a.value);
for(int i = 0 ; i < M; i++) {
while(listIdx < N && list.get(listIdx).mass <= backpack[i]) {
Crystal cur =list.get(listIdx++);
pq.add(new Crystal(cur.mass,cur.value));
}
if(!pq.isEmpty()) answer+=pq.poll().value;
}
System.out.println(answer);
}
}
'algorithm > problems' 카테고리의 다른 글
[백준 / Java] 1647번 : 도시 분할 계획 (0) | 2023.08.17 |
---|---|
[백준 / Java] 1644번 : 소수의 연속합 (0) | 2023.08.16 |
[백준 / Java] 1197번 : 최소 스패닝 트리 (0) | 2023.08.11 |
[백준 / Java] 17144번 : 미세먼지 안녕! (0) | 2023.08.08 |
[백준 / Java] 11053번 : 가장 긴 증가하는 부분 수열 (0) | 2023.08.04 |