https://www.acmicpc.net/problem/2343
문제
강토는 자신의 기타 강의 동영상을 블루레이로 만들어 판매하려고 한다. 블루레이에는 총 N개의 강의가 들어가는데, 블루레이를 녹화할 때, 강의의 순서가 바뀌면 안 된다. 순서가 뒤바뀌는 경우에는 강의의 흐름이 끊겨, 학생들이 대혼란에 빠질 수 있기 때문이다. 즉, i번 강의와 j번 강의를 같은 블루레이에 녹화하려면 i와 j 사이의 모든 강의도 같은 블루레이에 녹화해야 한다.
강토는 이 블루레이가 얼마나 팔릴지 아직 알 수 없기 때문에, 블루레이의 개수를 가급적 줄이려고 한다. 오랜 고민 끝에 강토는 M개의 블루레이에 모든 기타 강의 동영상을 녹화하기로 했다. 이때, 블루레이의 크기(녹화 가능한 길이)를 최소로 하려고 한다. 단, M개의 블루레이는 모두 같은 크기이어야 한다.
강토의 각 강의의 길이가 분 단위(자연수)로 주어진다. 이때, 가능한 블루레이의 크기 중 최소를 구하는 프로그램을 작성하시오.
입력
첫째 줄에 강의의 수 N (1 ≤ N ≤ 100,000)과 M (1 ≤ M ≤ N)이 주어진다. 다음 줄에는 강토의 기타 강의의 길이가 강의 순서대로 분 단위로(자연수)로 주어진다. 각 강의의 길이는 10,000분을 넘지 않는다.
출력
첫째 줄에 가능한 블루레이 크기중 최소를 출력한다.
예시 입출력
접근 방법
이 문제는 이분탐색을 이용하여 해결할 수 있다. 이분탐색을 사용하는 근거는 다음과 같다.
- "가능한 블루레이의 크기 중 최소를 구하는 프로그램"과 같이 최대값과 최소값을 구하는 문제이다.
- 문제에서 입력범위가(N의 입력값은 최대 100,000개) 단순 완전 탐색을 이용하기엔 범위 값이 크다.
- 탐색 범위가 명확하다.
- 타겟 : 블루레이의 개수
- 최소값 : 블루레이의 크기(M)는 주어진 강의 중 가장 큰 길이보다 작으면 안되므로 최소값이 된다.
- 최대값 : 블루레이 크기에 모든 강의 길이의 합에 모두 포함되는 경우이므로, 모든 길이의 합이 된다.
우선 이분탐색을 기본적으로 정렬된 리스트에서 시작이 된다. 여기선 블루레이의 크기의 최소값과 최대값이 순차적으로 정렬되었다는 가정하에 진행이 된다.
위에서 말한 탐색 범위를 보면 알듯이 최소값(=start), 최대값(=end)을 지정할 수 있다. 이것을 기반으로 시작하게 된다.
슈도코드
N(레슨 개수), M(블루레이 개수)
A(기타 레슨 데이터 저장 배열)
start(이진 탐색 시작 인덱스)
end(이진 탐색 종료 인덱스)
for (N값 만큼 반복)
{
A배열 저장하기
시작 인덱스 저장
종료 인덱스 저장
}
while (시작인덱스 <= 종료인덱스)
{
middle(중간인덱스)
count(현재 사용한 블루레이 개수)
sum(레슨 합)
for (N값 만큼 반복)
{
만약 sum + 현재 레슨 시간 > 중간 인덱스
count값 증가시키고 sum 리셋
sum값에 현재 레슨 시간 더하기
}
만약 sum 값이 0이 아니면, 이 후 값이 마지막 값을 담을 필요가 있다는 것이므로
count를 증가시킨다.
if(count > m) 시작 인덱스 = 중간 인덱스 + 1
else 종료 인덱스 = 중간 인덱스 - 1
}
시작 인덱스 출력하기
시작 인덱스가 종료인덱스가 커지는 순간에 종료가 되며(모든 탐색이 끝났다는 이야기), 그 순간의 값 `start`값이 최소값이 되게 된다. `count == m`때 종료되지 않는 것은 최소값을 찾아야 하기 떄문이다.
코드
package backjoon.silver.lv1;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class B2343 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
int M = Integer.parseInt(st.nextToken());
int[] A = new int[N];
int start = 0;
int end = 0;
st = new StringTokenizer(br.readLine());
for (int i = 0; i < N; i++) {
A[i] = Integer.parseInt(st.nextToken());
// 시작인덱스의 경우 주어진 강의 값 중 가장 큰 값입니다.
start = Math.max(start, A[i]);
// 종료인덱스는 모든 강의의 합이 블루레이 하나에 다 포함되는 경우이다.
end += A[i];
}
// 이분탐색
while (start <= end) {
int mid = (start + end) / 2;
int count = 0; // 블루레이 개수
int sum = 0; // 한 블루레이에 들어가는 합계
// N번 돌면서 mid값으로 만들 수 있는 count값을 계산한다.
for (int i = 0; i < N; i++) {
if (sum + A[i] > mid) {
count++;
sum = 0;
}
sum += A[i];
}
// 마지막값에 대해 카운팅되지 않는 값이 존재한다는 이야기므로 count를 증가시킨다.
if (sum > 0) {
count++;
}
if (count > M) {
start = mid + 1;
} else {
end = mid - 1;
}
}
System.out.println(start);
}
}
이와 같이 `타켓에 대한 탈출조건`이 없다면, 종료시점에 최소값은 `start`, 최대값은 `end`이 된다.
'TIL' 카테고리의 다른 글
[TIL-25/01/21] 99클럽 코테 스터디 5일차 - 백준 2470: 두 용액 - JAVA (0) | 2025.01.21 |
---|---|
[TIL-25/01/20] 99클럽 코테 스터디 6일차 - 백준 1260: DFS와 BFS - JAVA (0) | 2025.01.21 |
[TIL-25/01/14] 99클럽 코테 스터디 1일차 - 백준 2776: 암기왕 - JAVA (0) | 2025.01.14 |
[TIL-24/11/26] 99클럽 코테 스터디 30일차 TIL - 백준 1524: 세준세비 - JAVA (0) | 2024.11.26 |
[TIL-24/11/24] 99클럽 코테 스터디 28일차 TIL - 리트코드 506.Relative-Ranks - JAVA (0) | 2024.11.25 |