2022 03 18
2022-03-18
PriorityQueue 활용하여 문제 풀기
- 해당 방식이 시간 초과가 난 이유
- 정렬 O(NlogN)
- 넣을 수 있는 가방 이분 탐색 O(logN) * 보석 갯수 O(M)
- 보석 For문 돌면서 매번 이분탐색 <= 병목!
- PriorityQueue 사용
- 보석 무게 오름차순으로 정렬 (가벼운 -> 무거운)
- 가방 무게 오름차순으로 정렬 (가벼운 -> 무거운)
- 가방 for문 돌면서...
- 보석 while문 돌자!
- 현재 가방 무게 >= 보석 무게 의 경우, 가방에 담을 수 있다는 뜻이니!
- PriorityQueue를 만들어 보석의 가격만 담아두자!
- 보석 while문이 끝나면, PQ에서 poll 해서 가장 비싼 가격을 더하자 (해당 가방으로 담을 수 있는 가장 비싼 보석의 가격)
- 이미 더 가벼운 무게의 보석들은 PQ에 담았으니, 나머지 for문 진행 착착!
- PQ 방식 시간 복잡도 계산
- 정렬 O(NlogN)
- For문을 한번에 돌면서 O(보석 수 + 가방 수) 를 통해서 해결 할 수 있음
- PQ를 씀으로써 기존의 O(MlogN) 을 O(M + N)으로 단축!
import java.util.*;
class Main {
public static List<Treasure> treasures = new ArrayList<>();
public static List<Integer> bags = new ArrayList<>();
public static int bagSize;
public static void main(String args[]) {
Scanner in = new Scanner(System.in);
int treasureNumber = in.nextInt();
int bagNumber = in.nextInt();
for(int i=0; i<treasureNumber; i++) {
int weight = in.nextInt();
int price = in.nextInt();
treasures.add(new Treasure(weight, price));
}
for(int i=0; i<bagNumber; i++) {
bags.add(in.nextInt());
}
Collections.sort(treasures);
Collections.sort(bags);
long answer = 0;
Queue<Integer> queue = new PriorityQueue<>(Collections.reverseOrder());
int j=0;
for(int i=0; i<bagNumber; i++) {
int currentBag = bags.get(i);
while(j < treasureNumber && treasures.get(j).weight <= currentBag) {
queue.add(treasures.get(j).price);
j++;
}
if (!queue.isEmpty())
{
answer+=queue.poll();
}
}
System.out.println(answer);
}
}
class Treasure implements Comparable<Treasure>
{
int weight;
int price;
Treasure(int weight, int price) {
this.weight = weight;
this.price = price;
}
@Override
public int compareTo(Treasure o) {
return this.weight - o.weight;
}
}
재귀와 하노이의 탑
- 문제: https://brenden.tistory.com/31
- 하노이의 탑
- n개의 원판을 A -> C로 이동하는 경우의 수
1. 작은 원판 n-1 개를 A -> B 이동
2. 큰 원판 1개 A -> C 이동
3. 작은 원판 n-1 개를 B -> C 이동
- "원반 n개를 이동하는 문제는 원반 n-1개로 이동하는 문제로 세분화되고, 결국 원반 1개를 이동하는 문제로 세분화 된다고 보면 됩니다"
- 코드
// from에 꽂힌 num개의 원반을 by를 거쳐 to로 이동
public static void moveHanoiTower(int num, int from, int by, int to) {
if (num == 1) {
System.out.println("원반" + num + "을 " + from + "에서 " + to + "로 이동");
} else {
// STEP1. num-1 개 A에서 B로 이동 (C를 거쳐서)
moveHanoiTower(num - 1, from, to, by)
// STEP2. 가장 큰 원판 A -> C
System.out.println("원반" + num + "을 " + from + "에서 " + to + "로 이동");
// STEP3. num-1 개 B에서 C로 이동 (A를 거쳐서)
moveHanoiTower(num-1, by, from, to);
}
}