[BOJ6236] 용돈 관리 & [자료구조] 파라메트릭 서치

2 분 소요

[BOJ6236] 용돈 관리 & 파라메트릭 서치

파라메트릭 서치란?

  • 이진 탐색은 정렬된 일련의 값들이 주어졌을 때 그 값들 중에서 원하는 값을 찾는 알고리즘.
  • 이진 탐색은 처음에 중간값을 선택하여 그 값과 찾으려는 값을 비교하여 클 경우 선택했던 중간값을 최소값으로, 작을 경우 중간값을 최대값으로 하여 원하는 값을 찾을 때까지 반복하는 알고리즘.
  • 시간복잡도는 O(logN)
  • 이진 탐색과 매우 유사하고 동일한 원리를 가지지만, 활용의 차이가 다소 있다.
  • 주어진 범위 내에서 원하는 값 또는 원하는 조건에 가장 일치하는 값을 찾아내는 알고리즘.
  • 최적화 문제를 결정 문제로 바꾸어 풀 수 있게 되어 문제 접근이 상당히 용이해진다.
  • 파라메트릭 서치의 쉬운 예시 문제 : 자동차를 탈 수 있는 사람 중 나이가 가장 어린 사람을 찾고자 한다. 이 때 자동차를 탈 수 있는 사람이라 함은 나이가 19세 이상이라고 가정한다.
  • 위와 같은 예시를 통해 가장 어린 사람을 찾는 문제에서 이사람이 자동차를 탈 수 있는지의 결정문제로 바꾸어 해결하면 파라메트릭 서치를 정확히 사용했다고 할 수 있다.

문제 설명

  • N일 동안 하루에 얼마를 쓸 수 있는지 사용할 금액이 정해지고, M번만큼 출금할 수 있다.
  • 통장에서 출금한 돈으로 사용하다가 돈이 다 떨어지면 새로 같은 금액만큼 출금할 수 있다.
  • 돈이 남아있더라도 그날 사용할 금액이 더 큰 경우 돈을 넣고, 새로 같은 금액만큼 출금할 수 있다.
  • M번 출금횟수를 정확히 맞추기 위해 돈이 남더라도 다시 넣고 새로 출금할 수 있다.
  • 이 때 최소 인출 금액 K를 출력하는 문제

코드 리뷰

  • 파라메트릭 서치를 사용하여 통장에서 인출해야할 최소 금액을 구하는 문제에서 특정 금액을 인출했을 경우 예산대로 돈을 사용할 수 있는가에 대한 결정문제로 변환하여 푼다.
  • 즉 N일 동안 사용금액중 최대 금액~ N일 동안의 사용금액 총합까지의 범위를 이진탐색을 이용하여 그 금액으로 M번만큼 출금하여 N일을 사용할 수 있는지를 확인한다.
  • 가능하거나 불가능한 상황에 맞춰 금액의 범위를 줄여나간다. 그 후 그 범위 중 최소 값을 출력하면 된다.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;


int N, M;
vector <int> board;
int ans = 1000000000;

void bs(int left, int right) {
	if (left > right) return;
	int mid = (left + right) / 2;
	int cnt = 1, num = mid;
	for (int n = 0; n < N; n++) {
		if (board[n] > mid) break;
		else {
			if (board[n] <= num) {
				num -= board[n];
			}
			else {
				cnt++;
				num = mid;
				num -= board[n];
			}
		}
	}
	if (cnt <= M) {
		ans = min(ans, mid); //조건이 맞는 가능한 값들에 대해 가장 최적의 조건을 찾아가는 과정
		bs(left, mid - 1);
	}
	else { // 조건에 맞지 않는 범위들은 이진탐색방식으로 버려준다.
		bs(mid + 1, right);
	}
}

int main() {
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cin >> N >> M;
	int min_range = 0, max_range = 0;
	for (int n = 0; n < N; n++) {
		int num;
		cin >> num;
		board.push_back(num);
		max_range += num;
		if (min_range < num) min_range = num;
	}
	bs(min_range, max_range);
	cout << ans << "\n";
	return 0;
}

댓글남기기