※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※
이번에 볼 문제는 백준 9460번 문제인 메탈이다.
문제는 아래 링크를 확인하자.
https://www.acmicpc.net/problem/9460
9460번: 메탈
첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스의 첫째 줄에는 점(금속)의 개수 n과 k가 주어진다. (2 ≤ n ≤ 10,000) 다음 줄에는 점 p1, p2, ..., pn의 좌표를 나타내는 정수 2n개 (x1, y
www.acmicpc.net
주어진 금속을 전부 채굴하기 위한 최소비용을 구하는 문제이다.
금속의 총 채굴 비용 cost가 고정된 값으로 주어진다면 이 때 필요한 최소 수평터널의 개수를 구하는 것은 그리디한 방식으로 구해낼 수 있음을 관찰하자. 또한, cost가 증가하면 필요한 최소 수평터널의 개수는 단조감소하는 관계가 있음을 관찰하자.
위의 관찰을 이용해 총 채굴비용으로 가능한 값의 범위를 처음에는 전체 범위로 잡고 이진탐색을 통해 단계마다 절반씩 줄여나가 문제를 해결하자.
문제의 답은 항상 .0 또는 .5와 같은 소수점 한자리로 떨어지는, 즉 정수 혹은 정수의 절반꼴로 떨어짐을 관찰해 이진탐색을 부동소수점 범위까지 할 필요 없게끔 적절히 조절할 수 있다. 값이 그렇게 떨어지는 이유는 각 터널에서 채굴할 수 있는 가장 높은 위치의 금속과 낮은 위치의 고저차가 정수로 떨어진다는 점을 관찰해 알아낼 수 있다.
아래는 제출한 소스코드이다.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int T;
int N, K;
pair<int, int> points[10000];
int func(int x) {
int ret = 1;
int rangeL = points[0].second - x, rangeR = points[0].second + x;
for (int i = 1; i < N; i++) {
int tmpL = points[i].second - x, tmpR = points[i].second + x;
if (rangeR < points[i].second || points[i].second < rangeL) ret++, rangeL = tmpL, rangeR = tmpR;
else rangeL = max(rangeL, tmpL), rangeR = min(rangeR, tmpR);
}
return ret;
}
void solve() {
cin >> N >> K;
for (int i = 0; i < N; i++) cin >> points[i].first >> points[i].second;
sort(points, points + N);
int L = 0, R = 200000000;
while (L < R) {
int mid = (L + R) / 2;
if (func(mid) <= K) R = mid;
else L = mid + 1;
}
if (L & 1) cout << L / 2 << ".5\n";
else cout << L / 2 << ".0\n";
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> T;
while (T--) solve();
}
728x90
'BOJ' 카테고리의 다른 글
[BOJ 9464 // C++] 직사각형 집합 (1) | 2023.10.02 |
---|---|
[BOJ 9457 // C++] 기하학문양 (0) | 2023.10.01 |
[BOJ 2318 // C++] 상사 찾기 (0) | 2023.09.29 |
[BOJ 11341 // C++] Eakspay igpay atinlay? (0) | 2023.09.28 |
[BOJ 6080 // C++] Bad Grass (0) | 2023.09.27 |