문제
https://www.acmicpc.net/problem/17179
17179번: 케이크 자르기
첫 번째 줄에 자르는 횟수가 담긴 목록의 길이 N과 자를 수 있는 지점의 개수 M, 그리고 롤 케이크의 길이인 정수 L이 주어진다. (1 ≤ N ≤ M ≤ 1,000, 1 < L ≤ 4,000,000) 다음 M줄에 걸쳐 자를 수 있는
www.acmicpc.net
문제 요약
길이가 L인 롤 케이크가 있고, 이 케이크에는 자를 수 있는 지점이 M군데 존재한다.
자르는 횟수가 주어졌을 때, 가장 작은 조각의 길이의 최댓값을 출력한다.
코드
#include<iostream>
using namespace std;
#define MAX 1000
int n, m, length;
int point[MAX]; // 자를 수 있는 지점 저장
int target[MAX]; // 잘라야 하는 횟수
void binarySearch() {
for (int j = 0; j < n; j++) {
int left = 0;
int right = length;
while (left <= right) {
int mid = (left + right) / 2; // 가장 작은 조각의 길이의 최대 값
int prev = 0; // 마지막으로 자른 위치
int cut = 0; // 자를 수 있는 횟수
// mid보다 긴 구간을 자를 수 있는 개수 구하기
for (int i = 0; i < m; i++) {
if (point[i] - prev >= mid) { // 자른 길이가 mid 보다 크면
prev = point[i]; // prev에 자른 위치 저장 (자른 상태)
cut++; // 자를 수 있는 횟수 증가
}
}
// 잘라야하는 횟수와 자를 수 있는 횟수가 같은데, 마지막 조각의 길이가 mid보다 작거나
// 자를 수 있는 횟수보다 잘라야하는 횟수가 더 많으면,
if ((target[j] == cut && length - prev < mid) || cut < target[j]) {
right = mid - 1; // 가장 작은 조각의 길이를 줄인다. -> 자를 수 있는 횟수 증가
}
else {
left = mid + 1; // 가장 작은 조각의 길이를 늘린다. -> 자를 수 있는 횟수 감소
}
}
cout << right << "\n";
}
}
int main() {
//자르는 횟수 목록 길이. 자를수 있을 수 있는 지점 수, 롤 케이크 길이
cin >> n >> m >> length;
for (int i = 0; i < m; i++) {
cin >> point[i];
}
for (int i = 0; i < n; i++) {
cin >> target[i];
}
binarySearch();
return 0;
}
코드 설명
1. 정보를 입력 받는다.
1 - 1.자르는 횟수가 담긴 목록의 길이 N과, 자를 수 있는 지점의 개수 M, 롤 케이크의 길이 L을 입력 받는다.
1 - 2. 자를 수 있는 지점을 나타내는 정수를 입력 받고, 배열 point에 저장한다.
1 - 3. 자르는 횟수들을 입력 받고, 배열 target에 저장한다.
2. 이진 탐색을 진행한다.
2 - 1. 가장 작은 조각의 최대 길이를 mid로 설정하고, left는 0, right는 L, 즉 L의 절반부터 탐색한다.
+ left 포인터가 right 포인터의 왼쪽에 있을 동안만 탐색한다.
2 - 2. 자를 수 있는 지점을 하나씩 체크하여 mid보다 긴 구간이 발생하면 (자를 수 있으면) prev변수에 위치를 저장하여 자른다. (자를 때마다 cut을 1씩 증가시키며 자른 횟수 체크)
+ point[i] - prev는 현재 체크하는 자를 수 있는 지점에서 가장 최근에 잘랐던 지점을 뺀 값. 즉 point[i] 구간을 잘랐을 경우 구간 길이
2 - 3. 자를 수 있는 횟수(cut)보다 잘라야 하는 횟수(target[j])가 더 많으면 가장 작은 조각의 최대 길이를 줄여 자를 수 있는 횟수를 증가시키고, 더 적으면 가장 작은 조각의 최대 길이를 늘려 자를 수 있는 횟수를 감소시킨다.
+ 2 - 2에서 마지막 조각의 길이는 고려하지 못하므로, 잘라야하는 횟수와 자를 수 있는 횟수가 같으나, 마지막 조각의 길이가 mid보다 작다면 (가장 작은 조각의 길이가 mid가 아니므로) 가장 작은 조각의 최대 길이를 줄인다.
+ 조건에서 cut <= target[j]이 아닌 이유는 최대 길이을 구하는 문제이기 때문이다.
target[j]에 해당하는 길이를 찾았을 때, 더 긴 길이도 가능한지 탐색을 해야한다.
+ right를 출력하는 이유는 target[j]에 해당하는 길이를 찾았을 때, (cut == target[j]일 경우) left가 갱신, right는 고정이다, left가 right보다 클 때, 반복이 종료되므로 최종 길이는 right에 존재한다.
'Algorithm Problems > 이진 탐색' 카테고리의 다른 글
[백준/C++] 12015번: 가장 긴 증가하는 부분 수열 2 (1) | 2024.02.03 |
---|---|
[백준/C++] 6236번: 용돈 관리 (1) | 2024.02.01 |
[백준/Python] 2110번: 공유기 설치 (2) | 2023.11.05 |
[백준/Python] 2805번: 나무 자르기 (1) | 2023.11.03 |
[백준/python] 17951번: 흩날리는 시험지 속에서 내 평점이 느껴진거야 (2) | 2023.08.21 |