일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 정렬
- lis
- MST
- 이분탐색
- 이진탐색
- 크루스칼
- 펜윅트리
- 에라토스테네스의 체
- dfs
- 브루트포스
- BFS
- DisjointSet
- 구현
- 그리디
- DP
- 누적합
- 수학
- LazyPropagation
- 이분매칭
- boj
- 다익스트라
- 플로이드와샬
- 백준
- 좌표압축
- 삼분탐색
- lca
- 투포인터
- 위상정렬
- 세그먼트트리
- 비트마스크
Archives
- Today
- Total
lastknight00
[백준] 수조(2)(2130) 본문
문제 링크 : [백준] 수조(2)(2130)
문제 설명
문제 설명이 어려우니 링크 참조 해주세요.
입력
N(수조의 갯수,1<=N<=50,000)
Bi(수조가 위치한 높이,0<=Bi<=1,000,000)
Hi(수조 자체의 높이,1<=Hi<=40,000)
Wi(수조의 가로 길이,1<=Wi<=40,000)
Di(수조의 세로 길이,1<=Di<=40,000)
V(물의 부피,1<=2,000,000,000)
4
11 7 5 1
15 6 4 1
5 8 5 1
19 4 8 1
78
출력
수면의 높이
17.00
카테고리
#이분탐색
시간 복잡도 상한
W,D는 수조의 면적을 구하기 위한 것으로 문제를 푸는 시간 복잡도에는 영향을 주지 않을 것 같습니다.
밑면부터 수조의 꼭대기가 위치할 수 있는 최대 높이까지 각 높이별로 물의 부피를 구한다면,
1,040,000 * 50,000 이므로 TLE가 됩니다.
대략 O(Nlog(B+H)) 정도가 상한이 될 것 같습니다.
해결 방법
- 앞서 스위핑과 누적합으로 푸는 방법을 살펴봤습니다만, 다른 방법으로도 풀 수 있습니다.
- N이 5만이고, H가 1,040,000이기 때문에 시간복잡도 상한에서 살펴봤듯이, O(NlogH)에도 풀 수 있습니다.
- 즉, 높이를 반씩 잘라가면서 각 수조별로 물이 차는 부피를 구해도 문제를 풀 수 있다는 얘기가 됩니다.
- 따라서 높이를 기준으로 이분탐색을 하면서, 적당한 높이를 만날 때 까지, 이분탐색으로 정답을 구할 수 있습니다.
- 이분탐색이 가능함을 확인하는 방법은 아래와 같습니다.
5-1. 높이가 높아 질수록, 수조에 담기는 물의 부피는 절대 작아지지 않습니다.(비내림차순)
5-2. 5-1의 조건에 의해 기준이 되는 높이에서의 물의 부피가 찾고자하는 부피보다 작다면, 높이를 높이고, 그렇지 않다면 높이를 낮추는 방식으로 찾을 수 있습니다. - 하지만 문제가 있습니다.
- 일반적인 이분탐색(파라메트릭 서치)은 답이 정수일 때만 가능합니다.
- 하지만 이분탐색을 다시 생각해본다면, 이분탐색이 정수만 가능한 이유는, 종료 조건이 l과 r의 관계가 같아지거나, 대소가 역전이 되는 경우까지 찾습니다.
- 여기서 이분탐색의 기능에 대해 다시 생각해봅니다.
- 이분탐색을 8과 같이 사용하는 이유는 우리가 일반적으로 정수 범위에서 사용하므로 이해하기, 구현하기 편하게 생각해서 그렇다고 봅니다.
- 실제로 이분탐색은 연산 한번에 정확도가 두배 증가한다고 보는 것이 더 정확할 것입니다.
- 범위가 210이었다면, 한번의 연산으로 정확도는 29, 두번의 연산으로는 28이 될 겁니다.
- 즉, 연산 한번에 범위가 반씩 줄어듭니다.
- H가 최대 1,040,000 이므로, 대략 20번이면 정수범위까지는 정확한 값을 찾을 수 있습니다.
- 여기서 l과 r을 소수범위까지 탐색하면서 대략 10번을 더하면 1/210의 오차까지 범위를 줄일 수 있을 겁니다.
- 대략 이분탐색을 30번 반복하며, 각 높이별로, 수조들을 순회하면서 수조별 물의 부피를 구해 결정함수의 값을 확인하여 l과 r을 조정하면서 답을 구할 수 있습니다.
시간복잡도
O(NlogH)
코드
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class Main {
public static int N, V;
public static float ANSWER;
public static Node[] INPUTBOX = new Node[50000];
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
Node[] BOX = Arrays.copyOf(INPUTBOX, N);
int highest = 0;
for(int i=0;i<N;i++){
Node node = new Node();
node.b = sc.nextInt();
node.h = sc.nextInt();
node.w = sc.nextInt();
node.d = sc.nextInt();
BOX[i]=node;
if(highest < node.b+node.h) {
highest = node.b+node.h;
}
}
V = sc.nextInt();
Arrays.sort(BOX, new Comparator<Node>() {
@Override
public
int compare(Node a, Node b){
return a.b - b.b;
}
});
double min = BOX[0].b;
double max = highest+1;
if(getSize(BOX, highest) < V) {
System.out.println("OVERFLOW");
return;
}
double mid = 0;
for(int i=0;i<50;i++){
mid = (max-min)/2 + min;
double volume = getSize(BOX, mid);
if(volume >= V) {
max = mid;
}else if(volume < V) {
min = mid;
}
}
System.out.format("%.2f%n", mid);
}
public static double getSize(Node[] BOX, double mid) {
double volume = 0;
for(int i=0;i<N;i++){
if(mid>=BOX[i].b+BOX[i].h) {
volume += BOX[i].w*BOX[i].d*BOX[i].h;
}else if(mid<BOX[i].h+BOX[i].b && mid > BOX[i].b) {
volume += BOX[i].w*BOX[i].d*(BOX[i].h-(BOX[i].h+BOX[i].b-mid));
}
}
return volume;
}
public static class Node {
public int b,h,w,d;
}
}
'PS' 카테고리의 다른 글
[백준] 민균이의 계략(11568) (0) | 2020.06.02 |
---|---|
[백준] 열차정렬(4198) (0) | 2020.06.02 |
[백준] 수조(1)(2130) (0) | 2020.06.01 |
[백준] 행렬 곱셈 순서(11049) (0) | 2020.06.01 |
[백준] 외판원 순회(2098) (0) | 2020.05.31 |
Comments