-
정답 아이디어
1. 크레인을 들 수 있는 무게에따라 역순 정렬, 박스도 역순 정렬 한다.
2. 역순 정렬 된 크레인을 앞에서부터 선택하며, 자신이 가질 수 있는 가장 큰 크기의 박스를 옮긴다.
3. 이 때 크레인이 박스를 옮기게 되면, 해당 크레인 idx를 1 늘려주고 다음 박스로 넘어간다.
Try 1. 메모리초과 (1%)
import java.util.*; import java.io.*; class Main { public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int N = Integer.parseInt(br.readLine()); int[] cr = new int[N]; StringTokenizer st = new StringTokenizer(br.readLine()); for (int i=0; i< cr.length;i++){ cr[i] = Integer.parseInt(st.nextToken()); } int M = Integer.parseInt(br.readLine()); int[] box = new int[M]; st = new StringTokenizer(br.readLine()); for (int i=0; i<box.length;i++){ box[i] = Integer.parseInt(st.nextToken()); } PriorityQueue<Integer> pq = new PriorityQueue<>((o1, o2) -> { return Integer.compare(o2, o1); }); for (int elem : box) pq.offer(elem); int time = 1; Queue<Integer> que = new ArrayDeque<>(); int boxCnt = 0; while (true) { int tmp = boxCnt; for (int i=0; i<cr.length; i++) { while (!pq.isEmpty()){ int bx= pq.poll(); if (bx <= cr[i]){ boxCnt++; break; } else { que.offer(bx); } } while (!que.isEmpty()) pq.offer(que.poll()); } if (boxCnt == box.length) { break; } if (tmp == boxCnt) { time = -1; break; } time++; } System.out.println(time); } }
우선순위 큐 하나와, 일반 큐 하나를 사용해 풀이했다.
먼저 BIg-O 계산이 틀렸다. 처음으로 든 생각으로는, O(NM) 정도가 들거라 생각했다.
어차피 각 크레인이 박스를 꺼내 사용하고나면, 우선순위 큐에서 해당 박스가 사라지기 때문에
time이 늘어나는 만큼, 탐색해야 될 박스의 개수가 줄어듦으로 인해 평균회귀되어 O(NM)이라고 생각했지만,
naive하게 생각했을 경우 O(NM^2) 정도가 든다. 더군다나 평균회귀 된다고 해도, 각 크레인이 박스를 꺼내고나면 시도해본 다른 박스들을 다시 pq에 넣어주는데, 이 부분 때문에 메모리초과가 날 것이다.
Try 2. 시간초과 (1%)
import java.util.*; import java.io.*; class Main { public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int N = Integer.parseInt(br.readLine()); int[] cr = new int[N]; StringTokenizer st = new StringTokenizer(br.readLine()); for (int i=0; i< cr.length;i++){ cr[i] = Integer.parseInt(st.nextToken()); } int M = Integer.parseInt(br.readLine()); Integer[] box = new Integer[M]; boolean[] visited = new boolean[M]; st = new StringTokenizer(br.readLine()); for (int i=0; i<box.length;i++){ box[i] = Integer.parseInt(st.nextToken()); } Arrays.sort(box, Collections.reverseOrder()); int time = 1; int boxCnt = 0; while (true) { int tmp = boxCnt; for (int i=0; i<cr.length; i++) { for (int j = 0; j < box.length; j++) { if (!visited[j] && box[j] <= cr[i]) { visited[j] = true; boxCnt++; break; } } } if (boxCnt == box.length) { break; } if (tmp == boxCnt) { time = -1; break; } time++; } System.out.println(time); } }
처음에 메모리 초과가 났을 때, Queue 2개를 사용한 것이 잘못됐다고 생각되었다. 그래서 Queue 두 개를 지우고, 해당 박스가 옮겨졌는지 체크하는 boolean 배열 하나를 추가한 형태로 구현했다.
여기서도 마찬가지로 naive하게 생각해보면 O(NM^2)의 시간복잡도를 가진다.
제일 큰 용량을 가진 크레인만 모든 박스를 옮길 수 있을 정도로 박스들의 크기가 크다고 생각해보면 이 때 O(NM^2)의 경우가 발생한다.
Try 3. 정답!
import java.util.*; import java.io.*; class Main { public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int N = Integer.parseInt(br.readLine()); Integer[] cr = new Integer[N]; StringTokenizer st = new StringTokenizer(br.readLine()); for (int i=0; i< cr.length;i++){ cr[i] = Integer.parseInt(st.nextToken()); } int M = Integer.parseInt(br.readLine()); Integer[] box = new Integer[M]; boolean[] visited = new boolean[M]; st = new StringTokenizer(br.readLine()); for (int i=0; i<box.length;i++){ box[i] = Integer.parseInt(st.nextToken()); } Arrays.sort(box, Collections.reverseOrder()); Arrays.sort(cr, Collections.reverseOrder()); int time = 1; int boxCnt = 0; while (true) { int tmp = boxCnt; int idx = 0; for (int j = 0; j < box.length; j++) { if (idx >= cr.length) break; if (!visited[j] && box[j] <= cr[idx]) { visited[j] = true; idx++; boxCnt++; } } if (boxCnt == box.length) { break; } if (tmp == boxCnt) { time = -1; break; } time++; } System.out.println(time); } }
O(M^2)를 보장하기 위해, 기존에 box만 정렬하는 방식에서 크레인의 크기도 같이 정렬해 가장 큰 크레인부터 해당 크레인이 옮길 수 있는 가장 큰 박스를 찾는 방식으로 구현했다.
가장 큰 크레인이 해당 박스를 옮기게 되면, 그 다음 크레인은 가장 큰 크레인이 옮긴 박스의 다음 인덱스에 존재하는 박스부터 탐색을 시작하면 된다. 이렇게 구현 할 경우, 각 크레인마다 다시 처음에 있던 박스부터 탐색하는 구간이 줄어들어 시간을 줄일 수 있게 된다.
'Baekjoon' 카테고리의 다른 글
백준(BOJ) 25381 - ABBC (0) 2023.12.13 백준(BOJ) 25401 - 카드바꾸기 (1) 2023.12.07 14502 - 연구소 (2) 2022.12.28 1074 - Z (0) 2022.12.07 2580 - 스도쿠 (0) 2022.05.30