체뚱로그

[백준/C++] 13397 - 구간 나누기 2 본문

PS/BOJ

[백준/C++] 13397 - 구간 나누기 2

sooyeoniya 2023. 11. 12. 20:46

풀이 시간: 3:25:29
시간 복잡도: O(nlogS) - S는 배열의 합(sum)을 의미, for문을 통해 0 ~ n까지 선형 탐색
공간 복잡도: O(n) - n은 배열의 크기
참고 코드

https://leesh111112.tistory.com/356
https://ohcode.tistory.com/17
https://8156217.tistory.com/46

 

본 문제는 정말 헷갈리는 문제였다.

결국 못풀고 솔루션을 참고하게 되었는데, 솔루션을 보고도 한참 헤맸던 문제이다.

특히 저 check 함수가 이해가 처음에 잘 되지 않아서 내 나름대로 코드를 이해하면서 주석을 달아보았다.

 

까먹지 않기를.

전체 코드

#include <iostream>
#include <limits.h> // INT_MAX 사용
using namespace std;

int n, m, A[5000]; // 배열 크기 n, 배열을 m개 이하의 구간으로 나눔, 배열 A의 최대 n의 크기는 5000
int sum = 0, ans = INT_MAX; // 무한대 정의, 대략 21억

bool check(int mid) { // 주어진 mid 값을 기준으로 배열을 m개 이하 구간으로 나눌 수 있는지 확인(mid 값이 유효한지 판단)
	int count = 1, maxX = A[0], minX = A[0]; // count를 1(첫 번째 구간), maxX와 minX를 첫 번째 원소 값으로 설정
	for (int i = 0; i < n; i++) { // 배열 전체 순회
		// 현재 구간의 최댓값과 최솟값 구하기
		maxX = max(A[i], maxX); 
		minX = min(A[i], minX);

		// 만약 현재 구간의 '구간의 최댓값'(최댓값-최솟값)이
		// 현재의 구간 점수 최댓값(mid)보다 크면 새로운 구간으로 시작
		// 왜냐하면 구간 점수의 최댓값을 최소로 하는 배열의 분할 방법을 찾는 것이기 때문
		if (maxX - minX > mid) {
			count++; // 새로운 구간 시작
			maxX = minX = A[i];
		}
	}
	// count(구간 개수)가 m(처음에 설정한 구간 개수)보다 많다는 것은
	// mid(현재 구간 점수의 최댓값)가 우리가 구하고자 하는 정답(실제 구간 점수의 최댓값)보다 너무 작다는 뜻
	// 다시 말해 현재 mid 값으로는 배열 m개 이하의 구간으로 나눌 수 없다는 뜻이므로 false 반환
	// 따라서 false를 반환하여 mid 값의 범위를 증가시켜야함
	// 그 반대의 경우에는 mid가 너무 크거나 적당하다는 뜻이므로 true를 반환하여 mid 범위를 감소시키거나 유지하면서 최솟값 갱신
	return m >= count;
}

int binary_search() { // 구간 점수 최댓값 이진 탐색
	// 구간 점수 최댓값(배열에 있는 수의 구간 별 최댓값-최솟값 중 최댓값)은 sum을 절대 넘지 않음
	int mid, left = 0, right = sum;
	while (left <= right) {
		mid = (left + right) / 2; // 임의의 구간 점수 최댓값 설정
		if (check(mid)) {
			right = mid - 1;
			if (mid < ans) ans = mid; // mid의 값(구간 점수 최댓값)이 현재 구간 점수의 최댓값보다 작을 경우 갱신
		}
		else left = mid + 1;
	}
	return ans;
}

int main(void) {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	cin >> n >> m;

	for (int i = 0; i < n; i++) {
		cin >> A[i];
		sum += A[i]; // 배열의 모든 원소의 합
	}
	cout << binary_search();
}

 

https://www.acmicpc.net/problem/13397

 

13397번: 구간 나누기 2

첫째 줄에 배열의 크기 N과 M이 주어진다. (1 ≤ N ≤ 5,000, 1 ≤ M ≤ N) 둘째 줄에 배열에 들어있는 수가 순서대로 주어진다. 배열에 들어있는 수는 1보다 크거나 같고, 10,000보다 작거나 같은 자연수

www.acmicpc.net

 

'PS > BOJ' 카테고리의 다른 글

[백준/C++] 5557 - 1학년  (0) 2023.11.19
[백준/C++] 17626 - Four Squares  (0) 2023.11.19
[백준/C++] 22944 - 죽음의 비  (0) 2023.11.12
[백준/C++] 1300 - K번째 수  (0) 2023.11.12
[백준/C++] 19637 - IF문 좀 대신 써줘  (0) 2023.11.12
Comments