본문 바로가기

백준

백준2512 - 예산

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

 

2512번: 예산

첫째 줄에는 지방의 수를 의미하는 정수 N이 주어진다. N은 3 이상 10,000 이하이다. 다음 줄에는 각 지방의 예산요청을 표현하는 N개의 정수가 빈칸을 사이에 두고 주어진다. 이 값들은 모두 1 이상 100,000 이하이다. 그 다음 줄에는 총 예산을 나타내는 정수 M이 주어진다. M은 N 이상 1,000,000,000 이하이다. 

www.acmicpc.net

이진탐색으로 푼 문제다. 이진탐색으로 풀어야 하니까 오름차순을 적용하였다. 예산을 찾을 때 가장 작은 예산을 찾는 범위의 시작으로 놓으면 틀린다. 왜냐하면 예산 총액이 처음에 불렀던 예산보다 작을 수 있기 때문이다. 이점을 지키고 예산을 찾았다면 답을 현재 찾은 예산으로 갱신하고 시작값을 현재 찾은 예산 + 1로 갱신한다.

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;

int main() {
	int n; //지방 자치단체 수
	int num; //예산
	int limit; //예산 총액
	int res = 0; //처음에 불렀던 예산을 모두 더한 결과
	int x; //답으로 채택할 최대 예산
	vector<int> v; //예산들의 정보

	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> num;
		v.push_back(num);
		res = res + num;
	}
	
	sort(v.begin(), v.end()); //오름차순 정렬
	
	cin >> limit;

	x = v[v.size() - 1];

	if (limit >= res) {
		cout << x;
	}
	else {
		int left = 0; //제일 처음 주어진 예산보다 총액이 작은 예산이 들어올 수 있음으로 v[0]라 하면 틀림
		int right = v[v.size() - 1]; //최대 예산

		//이진 탐색을 통하여 최대가 될 수 있는 예산을 찾는다.
		while (left <= right) {
			int ans = 0;
			int mid = (left + right) / 2;
			for (int i = v.size() - 1; i >= 0; i--) {
				int temp = v[i];
				if (temp > mid) { //처음에 불렀던 예산이 현재 찾은 예산보다 큰 경우
					temp = mid; //현재 찾은 예산으로 초기화
				}
				ans = ans + temp;
			}
			if (ans <= limit) {
				x = mid;
				left = mid + 1;
			}
			else {
				right = mid - 1;
			}
		}
		cout << x;
	}
}

'백준' 카테고리의 다른 글

백준9935 - 문자열 폭발  (0) 2019.12.23
백준2805 - 나무 자르기  (0) 2019.12.07
백준1987 - 알파벳  (0) 2019.12.04
백준2596 - 비밀편지  (0) 2019.12.02
백준17265 - 나의 인생에는 수학과 함께  (0) 2019.12.01