매일 BOJ

(매일 BOJ) C++ 2512번 예산

norepinephrine 2025. 7. 25. 12:01

이번 문제는 2512번 예산 문제이다.

접근법

이 문제의 알고리즘 분류를 까보면 이분탐색 활용해야 한다고 작성되어 있다. 

 

따라서

start 값은 1,

end 값은 예산 요청에서 가장 큰 값

으로 설정한 후 for문 안에서 sum 변수를 만들어 start와 end값을 기준으로 생성된

1) mid값보다 작으면 예산값을 더하고

2) mid값보다 크면  mid 값을 더하는 방식으로 처리했다.

 

이분탐색

# 핵심 개념

  • 정렬된 배열에서만 사용할 수 있음 (오름차순/내림차순 모두 가능)
  • 탐색 범위를 반으로 줄여가며 원하는 값을 찾음
  • 중간값(mid)을 기준으로 원하는 값이 왼쪽에 있는지, 오른쪽에 있는지를 판단

# 기본 구조

int binary_search(vector<int>& arr, int target) {
    int left = 0;
    int right = arr.size() - 1;

    while (left <= right) {
        int mid = (left + right) / 2;

        if (arr[mid] == target) return mid;       // 찾은 경우
        else if (arr[mid] < target) left = mid + 1; // 오른쪽 절반 탐색
        else right = mid - 1;                      // 왼쪽 절반 탐색
    }

    return -1; // 못 찾은 경우
}

 

# 시각화

더보기

배열:       [10, 20, 30, 40, 50, 60]
인덱스:       0   1   2   3   4   5
찾고 싶은 값: 40

1단계: mid = 2 → arr[2] = 30 → 40 > 30 → 오른쪽 탐색 (left = 3)
2단계: mid = 4 → arr[4] = 50 → 40 < 50 → 왼쪽 탐색 (right = 3)
3단계: mid = 3 → arr[3] = 40 → 찾았다!

# 주의사항

  • 정렬되어 있지 않으면 사용할 수 없음
  • 오버플로우 방지: mid = left + (right - left) / 2;를 쓰는 경우도 있음
  • start <= end 조건 또는 start < end 조건은 문제 유형에 따라 달라짐

 

작성코드

# include <bits/stdc++.h>
using namespace std;

int main (void){
    ios::sync_with_stdio(0); cin.tie(0);
    int n;
    cin >> n;
    vector<int> v;

    for (int i = 0; i < n; i++){
        int money;
        cin >> money; // 지방 예산 요청
        v.push_back(money);
    }

    int max;
    cin >> max; // 총예산
    sort(v.begin(),v.end());

    int start = 1;
    int end = v.back();

    int result;

    while(start <= end){
        int mid = (start + end)/2;
        int sum = 0;

        for(int i  = 0; i < v.size(); i++){
            if (v[i] <= mid) sum += v[i];
            else sum += mid;
        }
        if (sum > max) end = mid - 1;
        else{
            if (mid <= end){
                result = mid;
            }
            start = mid + 1;
        }
        
    }
    cout << result;
}