레이블이 Binary Search인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Binary Search인 게시물을 표시합니다. 모든 게시물 표시

2016년 11월 1일 화요일

2022 - 사다리

https://www.acmicpc.net/problem/2022
https://uva.onlinejudge.org/...&problem=1507


\(a, b, c\) 가 주어지면 \(k\) 를 구해내는 문제이다.

피타고라스로 A, B를 구해서 기울기를 구하고, 두 직선의 교점 방정식을 이용했다. 그리고 교점의 y 위치가 \(c\) 가 되는 순간을 구하도록 이분 탐색을 했다.

우선 a가 포함된 직선을 g(x), b가 포함된 직선을 f(x)라 한다면 아래와 같은 정보가 나온다.

\(
\begin{cases}
A = \sqrt{a^2 - k^2} \\
B = \sqrt{b^2 - k^2}
\end{cases}
\)

\(
\begin{cases}
f(x) = \frac{B}{k}x \\
g(x) = -\frac{A}{k}x+A
\end{cases}
\)

두 직선이 만나는 순간을 \( (c_0, c) \)라 한다면 \( f(c_0) = g(c_0) = c \) 이여야 한다.

\(
\begin{align}
f(c_0) = & \frac{B}{k}c_0 = c \\
& c_0 = \frac{k \cdot c}{B}
\end{align}
\)

\(g(c_0) = g(\frac{k \cdot c}{B}) = c\) 가 나온다면 정답일것이다.

k를 찾는 과정에서 \(f(c_0) \gt c\) 라면 높이가 더 높은 좌표이므로 \(c_0\)을 줄여야한다는 뜻이다. k를 줄이면 \(c_0\)도 줄어든다.

k를 조정해서 만들어진 적당한 x로 f(x) = g(x)가 성립하는 지 확인하면서, 결과에 따라 k를 다시 조정하면 정답이 나온다.

k를 찾는 구간을 줄일 때 epsilon을 1e-5로 설정했을 때는 오답이었다. 이분탐색이 중간에 잘못되고 있나 생각에 구글링하다가 더 작은 결과까지 해보도록 1e-9 로 바꿨더니 정답을 맞았다. 너무 허무함

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

#define INF 987654321

double a, b, c;

double g(double x, double k){
    double A = sqrt(a*a - k*k);
    return A - (A * x / k);
}

double f(double x, double k){
    return sqrt(b*b - k*k) * x / k;
}

int main(){
    while(~scanf("%lf %lf %lf", &a, &b, &c)){
        double l=0, r=min(a, b);
        
        while(r - l > 1e-9){
            double k = (l+r)/2.0;
            double c0 = k * c / sqrt(b*b - k*k);
            if(g(c0, k) > c){
                l = k;
            } else {
                r = k;
            }
        }
        
        printf("%.3lf\n", l);
    }
    return 0;
}

2016년 5월 10일 화요일

1477 - 휴게소 세우기

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

정답을 미리 가정하고 정답의 범위를 점차 줄여나가보자.
만약 정답(휴게소가 없는 최대 구간)이 $x$라면 몇 개의 휴게소를 지어야할까?

길이가 $L$인 도로에는 $\{a_0, a_1, \dots, a_{n-1}\}$ 과 같이 휴게소가 있다고 하자.
최대 구간의 길이가 $x$라면 $a_0$과 $a_1$ 사이에는 $\frac{a_1-a_0-1}{x}$개 만큼의 휴게소가 필요하다.

$x$의 범위를 점차 줄여나간다면 휴게소의 개수($C_x$)가 원하는 $M$개 이상인 순간이 문제의 정답이다.

휴게소의 개수 $C_x$가 너무 많다면, 휴게소가 너무 많이 지어졌다는 의미이다. 너무 많이 지은 이유는 구간의 길이 $x$가 너무 좁았기 때문이다. $x$ 범위의 하한을 높이면 된다.
너무 적은 경우에는 반대로 $x$ 범위의 상한을 낮춘다.

도로의 처음과 끝 사이에도 휴게소를 세울 수 있으니 위치가 $0$인 곳과 위치가 $L$인 곳에도 가상의 휴게소가 있다고 생각하자.

2016년 3월 8일 화요일

1484 - 다이어트

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

현재 몸무게를 a, 기억하는 예전 몸무게를 b라 했을 때 $a^2 - b^2 = G$ 가 되는 모든 a를 출력한다.

$1^2$ 부터 $10000^2$ 를 모두 저장하고 $b^2 + G$ 가 되는 제곱꼴(= $a^2$)를 이진탐색으로 찾았다.

2016년 3월 2일 수요일

9009 - 피보나치

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

주어진 정수 X를 X와 같거나 가장 가까운 작은 수로 계속 빼면 된다.
마치 동전을 큰 단위부터 거슬러주면 제일 적은 개수로 거슬러 줄 수 있듯이,
가능한 큰 수로 계속 빼면 그것이 최소 개수로 표현할 수 있는 피보나치 수의 합이다.

ACM ICPC 2012 인터넷예선 D번 Fibonacci Numbers

1208 - 부분집합의 합 2

1182 - 부분집합의 합 에서 시간 제한이 N=20 에서 N=40 으로 확장된 문제이다.

$2^{20}$ 은 약 100만이라 시간이 충분했지만, $2^{40}$ 은 1조에 가깝다.

문제를 아무리 봐도 좋은 생각이 안 나다가, 주변에서 몇가지 힌트를 받고 해결할 수 있었다.

N개의 정수로 이루어진 배열 a에서 모든 부분집합을 살피려면 위에 말한것과 같이 $2^{40}$ 이라 굉장히 힘들다. 하지만 반으로 나눠서 부분 집합을 살핀다면 이 문제를 해결할 수 있다.

배열 a를 반으로 나눈다. 즉, $ a_0, a_1, \dots a_n $ 을 $ a_0, a_1, \dots a_{n/2} $ 와 $ a_{n/2 +1}, \dots a_n $ 으로 나눈다.

그리고 $ a_0, a_1, \dots a_n $ 에서 나올 수 있는 부분 집합의 합을 A 라 하고 나머지 $ a_{n/2 +1}, \dots a_n $ 나올 수 있는 부분 집합의 합을 B 라 하자.

그럼 문제의 정답은 (A의 원소로만 가능한 경우) + (A+B로 가능한 경우) + (B로만 가능한 경우) 로 나타낼 수 있다.
각각의 배열을 만드는 시간은 $2^{20}$ 을 두 번 하면 되고, "A+B로 가능한 경우"는 배열 B에 S-A[i]의 원소가 있는 지를 확인하면 된다.

S=0 이고 a = [ -7, -3, -2, 5, 8 ] 같은 경우는 A = { [-7, -3] 으로 나타낼 수 있는 부분 집합들 } 이고 B = { [-2, 5, 8] 으로 나타낼 수 있는 부분 집합들 } 이다. 이를 자세히 적는다면 A = [ -7, -3, -10 ], B = [ -2, 5, 8, 3, 6, 11 ] 이다.
여기서 답은 (A의 원소로만 가능한 경우 = 0) + (A+B로 가능한 경우는 -3+3=0 으로 1개) + (B로만 가능한 경우 = 0) 으로 1 이다.

주의해야 할 점은, 원소가 같은 것이 여러 개 있을 수 있다. 예를 들어 A = [0, 2, 2], B = [2, 2, 4] 라면 각 숫자는 서로 다르기 때문에 따로 세어야하고 A+B 로 만들어지는 2+2 의 경우들도 모두 서로 다르게 조합된 것들이기 때문에 모두 세어야 한다. 같은 2+2 이지만 $A_1 + B_0$ 은 2 + 2 인 것이고, $A_2 + B_0$ 은 (0+2) + 2 이기 때문이다.

2016년 3월 1일 화요일

1072 - 게임

형택이가 앞으로 더해야 하는 판을 k 라고 할 때, 소수점을 버렸을 때, $\frac{Y+k}{X+k}$ != $\frac{Y}{X}$ 가 되는 가장 큰 정수 k 를 구하는 게 문제죠.

수의 변화가 일어나는 부분은 Y+k 가 2Y 가 되거나, X+k 가 2X 가 되는 경우인데, X만 증가하는 경우(지는 경우)는 없으므로 Y+k 가 2Y에 가까워지면서 $\frac{Y+k}{X+k} > \frac{Y}{X}$ 가 되는 정수 k를 구하면 됩니다.

비례방정식으로 아래처럼 나타낼 수 있습니다
$$ {Y+k} : {X+k} = 2Y : X $$
그리고 여기서 아래 수식을 만족해야 겠죠.
$$\frac{x^2}{\left(99x-100y\right)}\le k \in \mathbb Z$$
근데 수식으로 정리해서 했더니 잘 안되더군요.
답은 바이너리 서치로 해야하나봅니다.

근데 근사값을 계산할 때 주의해야 할 점은 위 식대로라면 k로 인한 차이가 0.01 을 넘기는 부분, 즉 $ \frac{y+mid}{x+mid} - \frac{y}{x} \ge 1e^{-2} $ 가 되어야 하지만,
소수의 부정확성 때문에 양 변에 100을 곱하여 1의 차이로 계산하면 됩니다. 다시 말해, $ 100\frac{y+mid}{x+mid} - 100\frac{y}{x} \ge 1 $ 와 같이 하면 됩니다.

3273 - 두 수의 합

$a_i + a_j = x$ 를 만들 수 있는 (i ,j)의 쌍의 갯수를 찾는 문제이다.

이를 변형하면 $a_i$ 에 대해서 $a_i = x - a_j$ 가 되게끔 하는 $a_j$를 찾으면 된다.

이진탐색을 이용하면 된다.

게시글 목록