https://www.acmicpc.net/problem/1166
코드설명
파라매트릭 서치(Paramatric Search)를 활용합니다.
문제를 풀어가면서 여러 조건들을 잘 적용해야했습니다.
1. 먼저 처음에 놓쳤었던 부분은, left + 0.000000001 부분입니다.
처음에는 left + 1 로 처리했었는데요, 생각해보면 A의 값의 절대/상대 오차는 10^-9 이기에 그 숫자만큼의 차이로 연산해야합니다.
while(left + 0.000000001 < right) {
...
...
...
두번쨰는, 연산과정에서 OverFlow 가능성입니다. 처음에 int 형을 사용하여 3개의 곱이 곱해지면서 최악의 경우 오버플로우가 발생했습니다. long 형으로 Casting하여 사용합니다. ( 피연산자 중 하나라도 long 형이면 자동으로 결과값이 long형으로 캐스팅되지만, 모두 캐스팅처리합니다.)
private static boolean isPossible(double A) {
//(long)형을 사용해야 연산과정에서 OverFlow가 발생하지 않는다.
long count = (long) (arr[0] / A) * (long) (arr[1] / A) * (long) (arr[2] / A);
if(count >= N) return true;
else return false;
}
세번째는, 시간초과입니다.
부동소수점 특성상 경우에 따라 left + 1e-9 가 항상 right보다 작을 수 있습니다.
이 의미는 mid가 연산되면서 1e-9 보다 작은 1e-10 레벨에서부터 mid값이 갱신됨을 의미합니다.
그래서 우리는 문제에서 절대/상대 오차를 10^-9 까지 허용하기에 iterations = 100 을 두어서 처리합니다.
iterations=100을 두면 사실상 2^100개까지 탐색할 수 있기에 충분히 탐색할 수 있습니다.
int iterations = 100;
while(iterations-- > 0 && left + 0.000000001< right) {
...
...
...
네번쨰는, left의 시작범위는 left = lo ( 0 )이다.
일반적으로 lo 는 가능한 최소값을 나타냅니다. 생각해보면 박스의 크기가 음수가 되는 경우를 의미하는데, 이는 이후에 답을 연산할떄 A의 길이가 음수로 표현되는 오류가 나타납니다.
10 1 1 1
을 처리하면 아래와 같이 비교하면 됩니다.
10 1 1 1
left = -1 로 처리할시
-0.9999999993
left = 0 처리할시
0.3333333340
left가 -1 로 처리되면서, mid값이 -0.xxx로 처리될 수 있다는 것을 유의하여 left = lo 로 수정합니다.
코드
정답코드입니다.
package Main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
private static int C, N, M, W, H, K, A, L;
private static int[] arr;
private static int answer = 0;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
arr = new int[3];
L = Integer.parseInt(st.nextToken());
W = Integer.parseInt(st.nextToken());
H = Integer.parseInt(st.nextToken());
arr[0] = L; arr[1] = W; arr[2] = H;
Arrays.sort(arr);
//가장 작은 숫자가 시작점입니다.
double answer = paramatricSearch(0, arr[0]);
System.out.println(String.format("%.10f", answer));
}
private static double paramatricSearch(double lo, double hi) {
double left = lo;
double right = hi + 1;
int iterations = 100;
while(iterations-- > 0 && left + 0.000000001< right) {
double mid = (left + right) / 2;
if(isPossible(mid) == true) {
left = mid;
}else {
right = mid;
}
}
return right;
}
private static boolean isPossible(double A) {
//(long)형을 사용해야 연산과정에서 OverFlow가 발생하지 않는다.
long count = (long) (arr[0] / A) * (long) (arr[1] / A) * (long) (arr[2] / A);
if(count >= N) return true;
else return false;
}
}