백준
[백준 2343번 기타 레슨 Java] 이진 탐색을 활용한 값 찾기
treesheep
2023. 10. 14. 09:54


이진 탐색은 시간 복잡도 O(log(n))을 가지는 효율적인 탐색 방법이라고 할 수 있다.
효율적인 탐색을 하기 위해서 맨 처음 탐색 구간을 적절하게 설정하는 것도 중요하다.
문제는 앞에서 부터 순차적으로 담아야 하므로 특정 블루레이 길이를 가지고 앞에서 부터 꾹꾹 눌러담으며 몇 개의 블루레이 개수로 강의들을 모두 담을 수 있는지 체크하면서 주어진 개수를 만족하는 블루레이의 최소길이의 값을 찾아나간다.
- 각 레슨의 길이 중 최대 길이보다 작은값으로 블루레이 길이를 설정하면 그 블루레이에 아에 강의를 못 담는 상황이 발생한다
- 예를들어 총 48시간의 강의를 4개의 블루레이를 담고 싶다면 블루레이 개당 길이는 최소 12가 되어야하는 건 맞지만, 레슨 길이중 16시간짜리가 있으면, 블루레이 탐색의 최소값은 16시간이 되어야 맞다. 탐색의 최댓값은 강의 시간의 총합으로 한다. 1개의 블루레이에 담을 수 있는 경우이다
- 두 최소 탐색 값과 최대 탐색 값에서 재귀를 이용한 이진 탐색을 시행하여 최적의 길이를 찾는다.
- 원하는 블루레이 개수를 맞추면서 블루레이 size를 줄일 수 있을 때 까지 이진 탐색을 시행한다.
아래는 코드이다
|
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
package page186;
import java.io.*;
import java.util.*;
public class Example2343 {
static int[] arr;
static int key;
static int n;
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
key = Integer.parseInt(st.nextToken());
arr = new int[n];
st = new StringTokenizer(br.readLine());
for (int i = 0; i < n; i++) {
arr[i] = Integer.parseInt(st.nextToken());
}
int max = arr[0];
int total = 0;
for(int i = 0; i<n; i++){ //각 레슨 중에서 최대값을 찾고, 레슨 시간의 총합을 구한다
total += arr[i];
if(max < arr[i])
max = arr[i];
}
System.out.println(BinaryS(max ,total));
}
public static int BinaryS(int lo, int hi) { //이진 탐색으로 최소의 블루레이 길이를 구하는 메소드.
if (lo > hi)
return lo;
int mid = (lo + hi) / 2;
int count = getCount(mid);
if (count > key) //원하는 블루레이 수보다 더 많이 나오면 블루레이 size를 늘리기 위해 우측 탐색
return BinaryS(mid + 1, hi);
else //원하는 key값 보다 작거나 같으면 블루레이 size를 줄이기 위해 좌측 탐색
return BinaryS(lo, mid - 1);
}
public static int getCount(int size) { //해당 사이즈로 레슨 영상을 받았을 때 몇 개의 블루레이가 필요한지 세는 메소드
int count = 0;
int sum = 0;
int i = 0;
while (i < n) {
if (sum + arr[i] <= size) {
sum += arr[i];
i++;
} else {
sum = 0;
count++;
}
}
count++;
return count;
}
}
|
cs |
문제의 파악이 쉽지 않은 문제이다.
어떻게 count를 해야 올바른 방법인가 고민이 많았지만, 오랫동안 생각해보니
블루레이 개수를 줄이길 원하고 뒤에서 담는 수고를 덜으려면 앞에서 순차적으로 담을 때 최대한 채울 수 있을 떄까지 강의를 눌러담는게 맞다.