Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

최's 먹공로그

BOJ1202 보석도둑 본문

Pro감옥

BOJ1202 보석도둑

ChoiSH313 2022. 9. 29. 21:23

<문제 요약>

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

(1) 총 N 개의 보석 각 보석에는 무게 M, 가격 V를 가지고 있다.

(2) 가방은 K개 가방에 담을 수 있는 최대 무게는 C, 가방에는 한 개의 보석만 넣을 수 있다(가방 무게랑 같거나 작은 보석)

(3) 상덕이가 훔칠 수 있는 보석의 최대 가격을 구하시오

 

<풀이흐름, Source Code>

보석의 가격이 큰 순서로 정렬, 가방의 무게가 가벼운 순서로 정렬

보석을 한개 씩 빼서 가방에 넣을 수 있는지 검사 → 둘다 정렬된 상태이기 때문에 보석을 다 넣으면 가장 최선으로 넣은거임

(1) 보석의 가격이 큰 순서로 정렬을 한다. 처음에는 구조체(weight, price)를 갖는 단순 배열을 생각했지만, 보석과 가방의 개수가 30만개이고 단순 배열의 Arrays.sort는 QuickSort로 최악의 경우 n^2의 시간복잡도이다.

그래서 다음에 생각한건 list를 사용해서 Collections.sort하는 방법, 이건 MergeSort를 사용해서 nLog(n)의 시간 복잡도를 갖는다.

list를 사용해서 해도 되지만 Pro시간에서는 가능하면 HeapSort를 사용하기 위해 HeapSort를 사용하는 우선순위큐를 사용. 우선순위큐에 add할 때 가격순으로 정렬하기 위해 compareTo()를 사용한다.

(2) 가방무게는 무게가 작은 순서로 정렬을 한다. 처음에는 역시 단순 배열을 생각했지만, 보석한개를 꺼내서 30만개의 가방을 다 탐색한다면 n^2의 시간복잡도가 나오기 때문에 이분탐색을 해야된다. 이분탐색을 위해서 TreeMap사용

(3) 이제 보석큐에서 한 개 꺼내서 가방트리 중 같거나 큰 값중 가장 작은 무게를 갖는 가방에 넣는다. ceillingKey()

넣을 수 있는 가방이 있으면 result에 누적합 해주고 bagCount를 갱신

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.PriorityQueue;
import java.util.StringTokenizer;
import java.util.TreeMap;

public class BOJ1202_보석도둑 {
	
	private static class Node implements Comparable<Node>{
		int weight;
		int price;
		Node(int weight, int price){
			this.weight = weight;
			this.price = price;
		}
		@Override
		public int compareTo(Node o) {
			return this.price <= o.price ? 1 : -1;
		}
	}
	static int N, K, M, V, C;
	static PriorityQueue<Node> pq = new PriorityQueue<>();
	static TreeMap<Integer, Integer> tm = new TreeMap<Integer, Integer>();
	
	public static void main(String[] args) throws IOException{
		input();
		System.out.print(cal());
	}

	private static void input() throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine(), " ");
		N = Integer.parseInt(st.nextToken());
		K = Integer.parseInt(st.nextToken());
		for(int in = 0; in < N; in++) {
			st = new StringTokenizer(br.readLine(), " ");
			M = Integer.parseInt(st.nextToken());
			V = Integer.parseInt(st.nextToken());
			pq.add(new Node(M, V));
		}
		for(int ik = 0; ik < K; ik++) {
			st = new StringTokenizer(br.readLine(), "");
			C = Integer.parseInt(st.nextToken());
			if(tm.containsKey(C)) {
				tm.put(C, tm.get(C) + 1);
			}
			else {
				tm.put(C, 1);
			}
		}
	}

	private static long cal() {
		long result = 0;
		while(!pq.isEmpty()) {
			Node n = pq.poll();
			int weight = n.weight;
			int price = n.price;
			if(tm.ceilingKey(weight) == null) {
				continue;
			}
			else {
				int bagWeight = tm.ceilingKey(weight);
				int bagCount = tm.get(bagWeight);
				if(bagCount > 0) {
					result += price;
					bagCount--;
					if(bagCount <= 0) {
						tm.remove(bagWeight);
					}
					else {
						tm.put(bagWeight, bagCount);
					}
				}
			}
		}
		return result;
	}
}

 

<문제 Issue>

(1) int는 -21억~21억이다. 처음에 result를 int로 설정 했는데 보석은 최대 30만개이고 가격은 최대 100만

그럼 result에 들어갈 수 있는 최대는 30만 * 100만이여서 21억을 훌쩍 넘는다. 그래서 result는 long으로 선언

 

<중요 정리>

(1) sort 들

Arrays.sort → Quick Sort 사용 최악의 경우(반대로 정렬) n^2의 시간 복잡도

Collections.sort → Merge Sort 사용 항상 nLog(n)의 시간 복잡도를 유지

우선순위 큐 → Heap sort 사용 nLog(n) 시간 복잡도

프로시험에서는 최대한 Heap sort를 사용하도록 하자

(2) implements Comparable

compareTo{

return this.price <= o.price

}

는 this.price가 현재 add하는 놈이고 o.price가 이미 자료구조 안에 있는 놈

o.price가 크면 return 1, this.price가 크면 return -1

'Pro감옥' 카테고리의 다른 글

BOJ5052 전화번호 목록  (4) 2022.10.06
BOJ25240 가희와 파일 탐색기2  (0) 2022.10.01
[자료구조] 힙(heap)  (10) 2021.04.29